<!DOCTYPE html>
<html lang="en-US" dir="ltr">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>存储引擎 | VitePress</title>
    <meta name="description" content="A VitePress site">
    <link rel="preload stylesheet" href="/notebook/assets/style.3dbfd0c2.css" as="style">
    
    <script type="module" src="/notebook/assets/app.8aaa4cbe.js"></script>
    <link rel="preload" href="/notebook/assets/inter-roman-latin.2ed14f66.woff2" as="font" type="font/woff2" crossorigin="">
    <link rel="modulepreload" href="/notebook/assets/chunks/framework.1336c4e5.js">
    <link rel="modulepreload" href="/notebook/assets/chunks/theme.20cddc0c.js">
    <link rel="modulepreload" href="/notebook/assets/2、数据库_MySQL_MySQL核心_进阶.md.61d16dff.lean.js">
    <script id="check-dark-light">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
  </head>
  <body>
    <div id="app"><div class="Layout" data-v-255ec12d><!--[--><!--]--><!--[--><span tabindex="-1" data-v-ae3e3f51></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-ae3e3f51> Skip to content </a><!--]--><!----><header class="VPNav" data-v-255ec12d data-v-7e5bc4a5><div class="VPNavBar has-sidebar" data-v-7e5bc4a5 data-v-0937f67c><div class="container" data-v-0937f67c><div class="title" data-v-0937f67c><div class="VPNavBarTitle has-sidebar" data-v-0937f67c data-v-86d1bed8><a class="title" href="/notebook/" data-v-86d1bed8><!--[--><!--]--><!--[--><img class="VPImage logo" src="/notebook/Vue.png" alt data-v-8426fc1a><!--]--><!--[-->任硕的文档<!--]--><!--[--><!--]--></a></div></div><div class="content" data-v-0937f67c><div class="curtain" data-v-0937f67c></div><div class="content-body" data-v-0937f67c><!--[--><!--]--><div class="VPNavBarSearch search" style="--vp-meta-key:&#39;Meta&#39;;" data-v-0937f67c><!--[--><!----><div id="docsearch"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><svg class="DocSearch-Search-Icon" width="20" height="20" viewBox="0 0 20 20" aria-label="search icon"><path d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-0937f67c data-v-7f418b0f><span id="main-nav-aria-label" class="visually-hidden" data-v-7f418b0f>Main Navigation</span><!--[--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>Java学前端</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/HTML+JS.html" data-v-2f2cfafc><!--[-->HTML+JS<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/CSS.html" data-v-2f2cfafc><!--[-->CSS<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/Vue2+%E7%BB%84%E4%BB%B6.html" data-v-2f2cfafc><!--[-->Vue2+组件<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/Vue3+%E7%BB%84%E4%BB%B6.html" data-v-2f2cfafc><!--[-->Vue3+组件<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/React.html" data-v-2f2cfafc><!--[-->React<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>软件测试</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95/%E6%B5%8B%E8%AF%95%E5%9F%BA%E7%A1%80.html" data-v-2f2cfafc><!--[-->测试基础<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95/%E5%8E%8B%E5%8A%9B%E6%B5%8B%E8%AF%95.html" data-v-2f2cfafc><!--[-->压力测试<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>多线程</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E5%B9%B6%E5%8F%91%20&amp;%20%E5%A4%9A%E7%BA%BF%E7%A8%8B/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-2f2cfafc><!--[-->基础篇<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E5%B9%B6%E5%8F%91%20&amp;%20%E5%A4%9A%E7%BA%BF%E7%A8%8B/%E5%B9%B6%E5%8F%91%E5%AE%8C%E5%96%84.html" data-v-2f2cfafc><!--[-->进阶篇<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>开发工具</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/Chrome.html" data-v-2f2cfafc><!--[-->Chrome<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/IDEA%E5%9F%BA%E7%A1%80.html" data-v-2f2cfafc><!--[-->IDEA基础<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/IDEA%E6%8F%92%E4%BB%B6.html" data-v-2f2cfafc><!--[-->IDEA插件<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/VS%20Code.html" data-v-2f2cfafc><!--[-->VS Code<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>消息中间件</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/RabbitMQ.html" data-v-2f2cfafc><!--[-->RabbitMQ<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/RocketMQ.html" data-v-2f2cfafc><!--[-->RocketMQ<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/Kafka.html" data-v-2f2cfafc><!--[-->Kafka<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/Canal.html" data-v-2f2cfafc><!--[-->Canal<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-0937f67c data-v-f6a63727><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-f6a63727 data-v-82b282f1 data-v-f3c41672><span class="check" data-v-f3c41672><span class="icon" data-v-f3c41672><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-82b282f1><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-82b282f1><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-0937f67c data-v-0394ad82 data-v-7bc22406><!--[--><a class="VPSocialLink no-icon" href="https://github.com/renshuo123/renshuo123.github.io" aria-label="github" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink no-icon" href="#" aria-label="twitter" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Twitter</title><path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/></svg></a><a class="VPSocialLink no-icon" href="https://github.com/" aria-label target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg t="1676028692954" class="icon" ...</path></svg></a><!--]--></div><div class="VPFlyout VPNavBarExtra extra" data-v-0937f67c data-v-40855f84 data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-a7b5672a><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="icon" data-v-a7b5672a><circle cx="12" cy="12" r="2"></circle><circle cx="19" cy="12" r="2"></circle><circle cx="5" cy="12" r="2"></circle></svg></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><!----><!--[--><!--[--><!----><div class="group" data-v-40855f84><div class="item appearance" data-v-40855f84><p class="label" data-v-40855f84>Appearance</p><div class="appearance-action" data-v-40855f84><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-40855f84 data-v-82b282f1 data-v-f3c41672><span class="check" data-v-f3c41672><span class="icon" data-v-f3c41672><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-82b282f1><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-82b282f1><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div></div></div><div class="group" data-v-40855f84><div class="item social-links" data-v-40855f84><div class="VPSocialLinks social-links-list" data-v-40855f84 data-v-7bc22406><!--[--><a class="VPSocialLink no-icon" href="https://github.com/renshuo123/renshuo123.github.io" aria-label="github" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink no-icon" href="#" aria-label="twitter" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Twitter</title><path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/></svg></a><a class="VPSocialLink no-icon" href="https://github.com/" aria-label target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg t="1676028692954" class="icon" ...</path></svg></a><!--]--></div></div></div><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-0937f67c data-v-e5dd9c1c><span class="container" data-v-e5dd9c1c><span class="top" data-v-e5dd9c1c></span><span class="middle" data-v-e5dd9c1c></span><span class="bottom" data-v-e5dd9c1c></span></span></button></div></div></div></div><!----></header><div class="VPLocalNav reached-top" data-v-255ec12d data-v-5cfd5582><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-5cfd5582><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="menu-icon" data-v-5cfd5582><path d="M17,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,11,17,11z"></path><path d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z"></path><path d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z"></path><path d="M17,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,19,17,19z"></path></svg><span class="menu-text" data-v-5cfd5582>Menu</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-5cfd5582 data-v-18201f51><button data-v-18201f51>Return to top</button><!----></div></div><aside class="VPSidebar" data-v-255ec12d data-v-845b8fc6><div class="curtain" data-v-845b8fc6></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-845b8fc6><span class="visually-hidden" id="sidebar-aria-label" data-v-845b8fc6> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Java</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E6%96%B0%E7%89%B9%E6%80%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java新特性</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E9%9B%86%E5%90%88.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java集合</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java高级</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Linux</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/Linux%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Linux基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/Linux%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Linux新特性</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/Shell.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Shell脚本</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/%E5%AE%9E%E7%94%A8%E8%84%9A%E6%9C%AC.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>实用脚本</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/%E8%BD%AF%E4%BB%B6%E9%83%A8%E7%BD%B2.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>软件部署</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Nginx</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E5%AE%9E%E6%88%98%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>实战篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E9%9D%A2%E8%AF%95%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>面试篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SSM</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/Maven.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Maven</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/Spring.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Spring</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/SpringMVC.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringMVC</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/SpringBatch.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringBatch</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SpringBoot</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E5%BA%94%E7%94%A8%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>应用篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E6%96%B0%E7%89%B9%E6%80%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>新特性</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E8%BF%90%E7%BB%B4&amp;%E5%8E%9F%E7%90%86.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>运维&原理</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SpringCloud</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringCloud</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/%E5%BF%85%E5%A4%87/Sentinel.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Sentinel</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SpringSecurity</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/SpringSecurity/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringSecurity基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/SpringSecurity/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringSecurity进阶篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/SpringSecurity/%E9%AB%98%E7%BA%A7%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringSecurity高级篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Mybatis & MybatisPlus</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Mybatis&amp;MybatisPlus/Mybatis.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Mybatis</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Mybatis&amp;MybatisPlus/MybatisPlus.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MybatisPlus</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Mybatis&amp;MybatisPlus/JPA.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>JPA</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Git & ChatGPT</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Git.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Git</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Github.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Github</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/ChatGPT.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ChatGPT</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Jenkins.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Jenkins</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Netty.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Netty</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible has-active" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>数据库</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><section class="VPSidebarItem level-1 collapsible has-active" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>MySQL</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E4%BC%98%E5%8C%96.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL优化</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E8%AE%BE%E8%AE%A1.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL设计</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E8%BF%90%E7%BB%B4.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL运维</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>分库分表</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>Redis</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E4%BC%98%E5%8C%96.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis优化</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E5%8E%9F%E7%90%86.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis原理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis高级</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E5%AE%9E%E6%88%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis实战</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/%E6%9C%AC%E5%9C%B0%E7%BC%93%E5%AD%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>本地缓存</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>MongoDB</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MongoDB/%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MongoDB基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MongoDB/%E6%95%B4%E5%90%88.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MongoDB进阶</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>ElasticSearch</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/ElasticSearch/1%E3%80%81ES%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/ElasticSearch/3%E3%80%81ES%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES高级</p><!--]--></a><!----></div><!----></div><!--]--></div></section><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/influxdb.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>InfluxDB</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Neo4j.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Neo4j</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>高并发 & 秒杀 & 分布式</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E5%88%86%E5%B8%83%E5%BC%8F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>分布式理论</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/%E5%BF%85%E5%A4%87/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>分布式锁</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E7%A7%92%E6%9D%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>秒杀</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E9%AB%98%E5%8F%AF%E7%94%A8.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>高可用</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E9%AB%98%E5%B9%B6%E5%8F%91.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>高并发</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>云原生</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%BA%91%E5%8E%9F%E7%94%9F/Docker.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Docker</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%BA%91%E5%8E%9F%E7%94%9F/K8S.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>K8S</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>可视化 & 监控</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/%E7%9B%91%E6%8E%A7%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>监控基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/%E7%9B%91%E6%8E%A7%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>监控进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/%E5%8F%AF%E8%A7%86%E5%8C%96%E5%A4%A7%E5%B1%8F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>可视化大屏</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/Zabbix.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Zabbix</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>学前端</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>HTML+CSS</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/1%E3%80%81HTML+CSS/HTML%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>HTML基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/1%E3%80%81HTML+CSS/CSS%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>CSS基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/1%E3%80%81HTML+CSS/%E7%BD%91%E9%A1%B5%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>网页进阶</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>JS+TS</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/JS%20%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>JS基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/JS%20%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>JS进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/ES6%20%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES6基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/ES6%20%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES6进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/TypeScript.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>TS基础</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>NodeJS</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/4%E3%80%81Node/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Node基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/4%E3%80%81Node/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Node进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/4%E3%80%81Node/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目实战</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>Vue</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue3/Vue3%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Vue3进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue3/Vue3%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Vue3高级</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue3/Vue3%E6%96%B0%E8%AF%AD%E6%B3%95.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Vue3新语法</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue2/Vue2%E9%A1%B9%E7%9B%AE.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目实战</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>小程序</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>小程序基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/%E5%B0%8F%E7%A8%8B%E5%BA%8F%E4%BC%98%E5%8C%96.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>小程序优化</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/uniapp.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>uniapp</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/%E5%B0%8F%E7%A8%8B%E5%BA%8F%E9%A1%B9%E7%9B%AE.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目实战</p><!--]--></a><!----></div><!----></div><!--]--></div></section><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>计算机基础</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>数据结构</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>操作系统</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>设计模式</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>计算机网络</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/UML.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>UML</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E7%AE%97%E6%B3%95/LeetCode.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>LeetCode</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>项目实战</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>云尚办公</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E4%BA%91%E5%B0%9A%E5%8A%9E%E5%85%AC/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>小兔鲜</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E5%B0%8F%E5%85%94%E9%B2%9C/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E5%B0%8F%E5%85%94%E9%B2%9C/%E8%BF%9B%E9%98%B6%E7%AF%871.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇1</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E5%B0%8F%E5%85%94%E9%B2%9C/%E8%BF%9B%E9%98%B6%E7%AF%872.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇2</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>地图</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>苍穹外卖</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E8%8B%8D%E7%A9%B9%E5%A4%96%E5%8D%96/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>黑马头条</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E8%BF%9B%E9%98%B6%E7%AF%872.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇2</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E9%AB%98%E7%BA%A7%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>高级篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E6%94%AF%E4%BB%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>支付</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%A1%B9%E7%9B%AE%E6%8E%A8%E8%8D%90.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目推荐</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0" data-v-845b8fc6 data-v-9b797284><!----><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/team.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>团队成员</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-255ec12d data-v-669faec9><div class="VPDoc has-sidebar has-aside" data-v-669faec9 data-v-6b87e69f><!--[--><!--]--><div class="container" data-v-6b87e69f><div class="aside" data-v-6b87e69f><div class="aside-curtain" data-v-6b87e69f></div><div class="aside-container" data-v-6b87e69f><div class="aside-content" data-v-6b87e69f><div class="VPDocAside" data-v-6b87e69f data-v-3f215769><!--[--><!--]--><!--[--><!--]--><div class="VPDocAsideOutline" data-v-3f215769 data-v-ff0f39c8><div class="content" data-v-ff0f39c8><div class="outline-marker" data-v-ff0f39c8></div><div class="outline-title" data-v-ff0f39c8>On this page</div><nav aria-labelledby="doc-outline-aria-label" data-v-ff0f39c8><span class="visually-hidden" id="doc-outline-aria-label" data-v-ff0f39c8> Table of Contents for current page </span><ul class="root" data-v-ff0f39c8 data-v-d0ee3533><!--[--><!--]--></ul></nav></div></div><!--[--><!--]--><div class="spacer" data-v-3f215769></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-6b87e69f><div class="content-container" data-v-6b87e69f><!--[--><!--]--><!----><main class="main" data-v-6b87e69f><div style="position:relative;" class="vp-doc _notebook_2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93_MySQL_MySQL%E6%A0%B8%E5%BF%83_%E8%BF%9B%E9%98%B6" data-v-6b87e69f><div><h1 id="存储引擎" tabindex="-1">存储引擎 <a class="header-anchor" href="#存储引擎" aria-label="Permalink to &quot;存储引擎&quot;">​</a></h1><h2 id="mysql体系结构" tabindex="-1">MySQL体系结构 <a class="header-anchor" href="#mysql体系结构" aria-label="Permalink to &quot;MySQL体系结构&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202302272047694.png" alt="image-20230227204740590" style="zoom:80%;"><ul><li><p><strong>连接层</strong>：最上层是一些客户端和链接服务，主要完成一些类似于连接处理、授权认证、及相关的安全方案。服务器也会为安全接入的每个客户 端验证它所具有的操作权限。</p></li><li><p><strong>服务层</strong>：第二层架构主要完成大多数的核心服务功能，如SQL接口，并完成缓存的查询，SQL的分析和优化，部分内置函数的执行。所有跨存 储引擎的功能也在这一层实现，如 过程、函数等。</p></li><li><p><strong>引擎层</strong>：存储引擎真正的负责了MySQL中数据的存储和提取，服务器通过API和存储引擎进行通信。不同的存储引擎具有不同的功能，这样我 们可以根据自己的需要，来选取合适的存储引擎。</p></li><li><p><strong>存储层</strong>：主要是将数据存储在文件系统之上，并完成与存储引擎的交互。</p></li></ul><h2 id="存储引擎简介" tabindex="-1">存储引擎简介 <a class="header-anchor" href="#存储引擎简介" aria-label="Permalink to &quot;存储引擎简介&quot;">​</a></h2><blockquote><p>存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式 。存储引擎是基于表的，而不是基于库的，所以存储引擎也可被 称为表类型。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220410092518555.png" alt="image-20220410092518555" style="zoom:67%;"><blockquote><p>存储引擎是MySQL的组件，用于处理不同表类型的SQL操作。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能，使用不同的存储引擎，还可以获得特定的功能。</p></blockquote><blockquote><p>使用哪一种引擎可以灵活选择，<strong>一个数据库中多个表可以使用不同引擎以满足各种性能和实际需求</strong>，使用合适的存储引擎，将会提高整个数据库的性能 。</p></blockquote><blockquote><p>MySQL服务器使用<strong>可插拔</strong>的存储引擎体系结构，可以从运行中的 MySQL 服务器加载或卸载存储引擎 。</p></blockquote><h2 id="存储引擎使用⭐" tabindex="-1">存储引擎使用⭐ <a class="header-anchor" href="#存储引擎使用⭐" aria-label="Permalink to &quot;存储引擎使用⭐&quot;">​</a></h2><h3 id="查看存储引擎" tabindex="-1">查看存储引擎 <a class="header-anchor" href="#查看存储引擎" aria-label="Permalink to &quot;查看存储引擎&quot;">​</a></h3><p>查看当前数据库支持的存储引</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 查看支持的存储引擎</span></span>
<span class="line"><span style="color:#A6ACCD;">show engines ;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 查看默认存储引擎</span></span>
<span class="line"><span style="color:#A6ACCD;">show variables </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%storage_engine%</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 查看具体某一个表所使用的存储引擎，这个默认存储引擎被修改了！</span></span>
<span class="line"><span style="color:#A6ACCD;">show </span><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">table</span><span style="color:#A6ACCD;"> tablename</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 准确查看某个数据库中的某一表所使用的存储引擎</span></span>
<span class="line"><span style="color:#A6ACCD;">show </span><span style="color:#F78C6C;">table</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">status</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">tablename</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">show </span><span style="color:#F78C6C;">table</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">status</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">database</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">name</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">tablename</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220410092745790.png" alt="image-20220410092745790" style="zoom:67%;"><h3 id="设置存储引擎" tabindex="-1">设置存储引擎 <a class="header-anchor" href="#设置存储引擎" aria-label="Permalink to &quot;设置存储引擎&quot;">​</a></h3><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 建表时指定存储引擎。默认的就是INNODB，不需要设置</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">table</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">t1</span><span style="color:#A6ACCD;">(</span></span>
<span class="line"><span style="color:#A6ACCD;">    id </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">primary key</span><span style="color:#A6ACCD;"> auto_increment,</span></span>
<span class="line"><span style="color:#A6ACCD;">    username </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">50</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">)engine </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> innodb;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- csv：不支持主键和自增，也不能为空</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">table</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">t2</span><span style="color:#A6ACCD;">(</span></span>
<span class="line"><span style="color:#A6ACCD;">    id </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">not null</span><span style="color:#A6ACCD;"> ,</span></span>
<span class="line"><span style="color:#A6ACCD;">    username </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">50</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">not null</span></span>
<span class="line"><span style="color:#A6ACCD;">)engine </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> csv;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- memory：创建方式同innodb</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">table</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">t3</span><span style="color:#A6ACCD;">(</span></span>
<span class="line"><span style="color:#A6ACCD;">    id </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">primary key</span><span style="color:#A6ACCD;"> auto_increment,</span></span>
<span class="line"><span style="color:#A6ACCD;">    username </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">50</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">)engine </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> memory;</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 修改存储引擎</span></span>
<span class="line"><span style="color:#F78C6C;">alter</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">table</span><span style="color:#A6ACCD;"> t2 engine </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> InnoDB;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 修改默认存储引擎，也可以在配置文件my.cnf中修改默认引擎</span></span>
<span class="line"><span style="color:#F78C6C;">SET</span><span style="color:#A6ACCD;"> default_storage_engine</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">NDBCLUSTER;</span></span></code></pre></div><blockquote><p>默认情况下，每当 <code>CREATE TABLE</code> 或 <code>ALTER TABLE</code> 不能使用默认存储引擎时，都会生成一个警告。为了防止在所需的引擎不可用时出现令人困惑的意外行为，可以启用 <code>NO_ENGINE_SUBSTITUTION SQL</code> 模式。如果所需的引擎不可用，则此设置将产生错误而不是警告，并且不会创建或更改表</p></blockquote><h2 id="存储引擎特点⭐" tabindex="-1">存储引擎特点⭐ <a class="header-anchor" href="#存储引擎特点⭐" aria-label="Permalink to &quot;存储引擎特点⭐&quot;">​</a></h2><h3 id="innodb" tabindex="-1">InnoDB <a class="header-anchor" href="#innodb" aria-label="Permalink to &quot;InnoDB&quot;">​</a></h3><blockquote><p>InnoDB是一种<strong>兼顾高可靠性和高性能</strong>的通用存储引擎，在 MySQL 5.5 之后，<strong>InnoDB是默认的 MySQL 存储引擎</strong></p><ul><li><p>DML操作<strong>遵循ACID模型</strong>，<strong>支持事务 ； 行级锁 ，提高并发访问性能</strong>；</p></li><li><p><strong>支持外键 FOREIGN KEY约束，保证数据的完整性和正确性</strong>；</p></li><li><p>xxx.ibd：xxx代表的是表名，innoDB引擎的每张表都会对应这样一个表空间文件</p></li><li><p>存储该表的表结构（frm、sdi）、数据和索引。</p></li></ul></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 看每一张表是不是都对应一个表空间文件,on表示每一张表都对应一个表空间</span></span>
<span class="line"><span style="color:#A6ACCD;">show variables </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">innodb_file_per_table</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209202027852.png" alt="image-20220920202705776" style="zoom:80%;"><blockquote><p>如果该参数开启，代表对于InnoDB引擎的表，每一张表都对应一个ibd文件。 我们直接打开MySQL的数据存放目录： C:\ProgramData\MySQL\MySQL Server 8.0\Data ， 这个目录下有很多文件夹，不同的文件夹代表不同的数据库，我们直</p></blockquote><p>接打开itcast文件夹。</p><blockquote><p>可以看到里面有很多的ibd文件，每一个ibd文件就对应一张表，比如：我们有一张表 account，就有这样的一个</p><p>account.ibd文件，而在这个ibd文件中不仅存放表结构、数据，还会存放该表对应的索引信息。 而该文件是基于二</p><p>进制存储的，不能直接基于记事本打开，我们可以使用mysql提供的一个指令 ibd2sdi ，通过该指令就可以从ibd文</p><p>件中提取sdi信息，而sdi数据字典信息中就包含该表</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220410094943137.png" alt="image-20220410094943137" style="zoom:67%;"><ul><li><p>表空间 : InnoDB存储引擎逻辑结构的最高层，ibd文件其实就是表空间文件，在表空间中可以包含多个Segment段。</p></li><li><p>段 : 表空间是由各个段组成的， 常见的段有数据段、索引段、回滚段等。InnoDB中对于段的管理，都是引擎自身完成，不需要人为对其控制，一个段中包含多个区。</p></li><li><p>区 : 区是表空间的单元结构，每个区的大小为1M。 默认情况下， InnoDB存储引擎页大小为16K， 即一个区中一共有64个连续的页。</p></li><li><p>页 : 页是组成区的最小单元，**页也是InnoDB **存储引擎磁盘管理的最小单元，每个页的大小默认为 16KB。为了保证页的连续性，InnoDB 存储引擎每次从磁盘申请 4-5 个区。</p></li><li><p>行 : InnoDB 存储引擎是面向行的，也就是说数据是按行进行存放的，在每一行中除了定义表时所指定的字段以外，</p><p>还包含两个隐藏字段(后面会详细介绍)。</p></li></ul><h3 id="myisam" tabindex="-1">MyISAM <a class="header-anchor" href="#myisam" aria-label="Permalink to &quot;MyISAM&quot;">​</a></h3><blockquote><p>1). MyISAM是MySQL早期的默认存储引擎</p><p>2). 特点</p><ul><li>不支持事务，不支持外键</li><li>支持表锁，不支持行锁</li><li>访问速度快</li></ul><p>3). 文件</p><ul><li>xxx.sdi：存储表结构信息</li><li>xxx.MYD: 存储数据</li><li>xxx.MYI: 存储索引</li></ul></blockquote><h3 id="memory" tabindex="-1">Memory <a class="header-anchor" href="#memory" aria-label="Permalink to &quot;Memory&quot;">​</a></h3><blockquote><p>1). 介绍：Memory引擎的表数据时存储在内存中的，由于受到硬件问题、或断电问题的影响，只能将这些表作为临时表或缓存使用。</p><p>2). 特点：内存存放，hash索引（默认）</p><p>3).文件：xxx.sdi：存储表结构信息，因为数据都是存放在内存中的</p></blockquote><h3 id="区别和对比⭐" tabindex="-1">区别和对比⭐ <a class="header-anchor" href="#区别和对比⭐" aria-label="Permalink to &quot;区别和对比⭐&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209202213395.png" alt="image-20220920221335214" style="zoom:80%;"><blockquote><p>InnoDB引擎与MyISAM引擎的区别 ?</p><p>①InnoDB引擎, 支持事务, 而MyISAM不支持</p><p>②InnoDB引擎, 支持行锁和表锁, 而MyISAM仅支持表锁, 不支持行锁</p><p>③InnoDB引擎, 支持外键, 而MyISAM是不支持的</p></blockquote><h2 id="存储引擎选择" tabindex="-1">存储引擎选择 <a class="header-anchor" href="#存储引擎选择" aria-label="Permalink to &quot;存储引擎选择&quot;">​</a></h2><p>在选择存储引擎时，应该根据应用系统的特点选择合适的存储引擎。对于复杂的应用系统，还可以根据实际情况选择多种存储引擎进行组合。</p><blockquote><p>InnoDB : <strong>是MySQL的默认存储引擎，支持事务、外键、行级锁。如果应用对事务的完整性有比较高的要求，在并发条件下要求数据的一致性，数据操作除了插入和查询之外，还包含很多的更新、删除操作，那么InnoDB存储引擎是比较合适的选择</strong>。</p></blockquote><blockquote><p>MyISAM ： 如果应用是以<strong>读操作和插入操作为主</strong>，<strong>只有很少的更新和删除操作</strong>，<strong>并且对事务的完整性、并发性要求不是很高</strong>，那 么选择这个存储引擎是非常合适的。<strong>被MongoDB替代</strong></p></blockquote><blockquote><p>MEMORY：<strong>将所有数据保存在内存中，访问速度快，通常用于临时表及缓存</strong>。<strong>MEMORY的缺陷就是对表的大小有限制，太大的表无法缓存在内存中，而且无法保障数据的安全性</strong>。<strong>被Redis替代</strong></p></blockquote><h1 id="索引⭐⭐" tabindex="-1">索引⭐⭐ <a class="header-anchor" href="#索引⭐⭐" aria-label="Permalink to &quot;索引⭐⭐&quot;">​</a></h1><p><a href="https://mp.weixin.qq.com/s?__biz=MzAwMjI0ODk0NA==&amp;mid=2451968393&amp;idx=1&amp;sn=e6fd24dddf556fe910ee6c2d6113769f&amp;chksm=8d1fe816ba686100d35650e0581ee9f9a248ccb9865315ed6f6285e19a9e5267d8b2769eded8&amp;mpshare=1&amp;scene=23&amp;srcid=02133fRhJyWezSai3VLLv9tO&amp;sharer_sharetime=1676261479364&amp;sharer_shareid=29b8a04db1dbd975e3bf4e9f47e7ac67#rd" target="_blank" rel="noreferrer">深入浅出 MySQL 索引（一）</a></p><h2 id="概述" tabindex="-1">概述 <a class="header-anchor" href="#概述" aria-label="Permalink to &quot;概述&quot;">​</a></h2><h3 id="什么是索引" tabindex="-1">什么是索引 <a class="header-anchor" href="#什么是索引" aria-label="Permalink to &quot;什么是索引&quot;">​</a></h3><blockquote><p>索引（index）是帮助MySQL<strong>高效获取数据的数据结构（有序）</strong>。在数据之外，数据库系统还维护着满足特定查找算法的数据结构，这些 数据结构以某种方式引用（指向）数据， 这样就可以在这些数据结构上实现高级查找算法，这种数据结构就是索引。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202302281050289.png" alt="image-20230228105028185" style="zoom:80%;"><h3 id="查询实例" tabindex="-1">查询实例 <a class="header-anchor" href="#查询实例" aria-label="Permalink to &quot;查询实例&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202302281051388.png" alt="image-20230228105156271" style="zoom:67%;"><h3 id="索引的优点" tabindex="-1">索引的优点 <a class="header-anchor" href="#索引的优点" aria-label="Permalink to &quot;索引的优点&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220410100933724.png" alt="image-20220410100933724" style="zoom:67%;"><h4 id="降低数据库的-i-o-成本" tabindex="-1">降低数据库的 I/O 成本 <a class="header-anchor" href="#降低数据库的-i-o-成本" aria-label="Permalink to &quot;降低数据库的 I/O 成本&quot;">​</a></h4><blockquote><p>这里其实就是减少数据库读写数据的花费的时间。假如让你从一堆杂乱中的书中找一本指定的书，是不是得一本一本的看下封面上写的书名是不是对的，有了索引，就不需要对每本书都翻看封面了，可以快速到那本书，减少了很多无效的查找。</p></blockquote><h4 id="保证数据的唯一性" tabindex="-1">保证数据的唯一性 <a class="header-anchor" href="#保证数据的唯一性" aria-label="Permalink to &quot;保证数据的唯一性&quot;">​</a></h4><blockquote><p>通过创建唯一索引，可以保证数据库表中每一行数据的唯一性。注意这里是唯一索引，通过关键字 UNIQUE 来创建唯一索引。比如说员工表中的每个员工 id 都是唯一的。</p></blockquote><h4 id="提高多表联合查询的效率" tabindex="-1">提高多表联合查询的效率 <a class="header-anchor" href="#提高多表联合查询的效率" aria-label="Permalink to &quot;提高多表联合查询的效率&quot;">​</a></h4><blockquote><p>不论是单表查询，还是多表查询，索引都是提高查询效率的。</p></blockquote><h3 id="索引的缺点" tabindex="-1">索引的缺点 <a class="header-anchor" href="#索引的缺点" aria-label="Permalink to &quot;索引的缺点&quot;">​</a></h3><h4 id="创建索引和维护索引要耗费时间" tabindex="-1">创建索引和维护索引要耗费时间 <a class="header-anchor" href="#创建索引和维护索引要耗费时间" aria-label="Permalink to &quot;创建索引和维护索引要耗费时间&quot;">​</a></h4><blockquote><p>就好比图书馆借书和还书都是需要图书管理员来的维护，如果长期没人管，图书不就又乱了吗？</p></blockquote><h4 id="索引需要占磁盘空间" tabindex="-1">索引需要占磁盘空间 <a class="header-anchor" href="#索引需要占磁盘空间" aria-label="Permalink to &quot;索引需要占磁盘空间&quot;">​</a></h4><blockquote><p>MySQL不仅要保存数据，还要保存一索引文件。建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重，但如果你在一个大表上创建了多种组合索引，索引文件会得膨胀很快。就好比图书馆对每本书的位置信息都是需要存放到一份数据里面的，如果是存放到电脑里面，就会占用电脑的硬盘空间，如果是用纸质文档来存储，则会占用房间的空间。</p></blockquote><h4 id="降低更新表的速度" tabindex="-1">降低更新表的速度 <a class="header-anchor" href="#降低更新表的速度" aria-label="Permalink to &quot;降低更新表的速度&quot;">​</a></h4><blockquote><p>就好比图书馆将新出的书放到书架之前，管理员是需要先查询下这本书的所属位置，再去放到书架上，这个查询的过程就会耗费一定的时间。</p></blockquote><h2 id="索引结构" tabindex="-1">索引结构 <a class="header-anchor" href="#索引结构" aria-label="Permalink to &quot;索引结构&quot;">​</a></h2><h3 id="索引结构分析" tabindex="-1">索引结构分析 <a class="header-anchor" href="#索引结构分析" aria-label="Permalink to &quot;索引结构分析&quot;">​</a></h3><p>MySQL的索引是在存储引擎层实现的，不同的存储引擎有不同的索引结构，主要包含以下几种：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209202239411.png" alt="image-20220920223917319"><p>上述是MySQL中所支持的所有的索引结构，接下来，我们再来看看不同的存储引擎对于索引结构的支持情况</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209202240975.png" alt="image-20220920224054886"><blockquote><p>我们平常所说的索引，如果没有特别指明，都是指<strong>B+树结构组织的索引</strong>。</p></blockquote><h3 id="索引数据结构" tabindex="-1">索引数据结构 <a class="header-anchor" href="#索引数据结构" aria-label="Permalink to &quot;索引数据结构&quot;">​</a></h3><p><a href="https://mp.weixin.qq.com/s?__biz=MzU1NTkwODE4Mw==&amp;mid=2247494255&amp;idx=1&amp;sn=ba97be88af7dcb808dabc27d74c015e4&amp;chksm=fbcf8757ccb80e41357540bb4df0e9027b47c5e2d6020a7ccd2497c0d95683e996452089f838&amp;mpshare=1&amp;scene=23&amp;srcid=0703640NLci6KrOUU8BmwwDl&amp;sharer_sharetime=1656778146534&amp;sharer_shareid=29b8a04db1dbd975e3bf4e9f47e7ac67#rd" target="_blank" rel="noreferrer">认真聊一下MySQL索引的底层实现！ (qq.com)</a></p><h4 id="二叉树" tabindex="-1">二叉树 <a class="header-anchor" href="#二叉树" aria-label="Permalink to &quot;二叉树&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209202242512.png" alt="image-20220122223557660" style="zoom:80%;"><blockquote><ul><li>二叉树缺点：<strong>顺序插入时，会形成链表，查询性能大大降低。 大数据量情况下，层级较深，检索速度慢</strong></li><li>红黑树：<strong>大数据量情况下，层级较深，检索速度慢</strong>。</li></ul></blockquote><h4 id="b-tree" tabindex="-1">B-Tree <a class="header-anchor" href="#b-tree" aria-label="Permalink to &quot;B-Tree&quot;">​</a></h4><p><strong>多路平衡查找树</strong></p><p>具体动态变化的过程可以参考网站: <a href="https://www.cs.usfca.edu/~galles/visualization/BTree.html" target="_blank" rel="noreferrer">B-Tree Visualization (usfca.edu)</a></p><p>节点最多存储4个key，5个指针</p><p>知识小贴士: <strong>树的度数指的是一个节点的子节点个数</strong></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220410101418648.png" alt="image-20220410101418648" style="zoom:67%;"><h4 id="b-tree-1" tabindex="-1">B+Tree <a class="header-anchor" href="#b-tree-1" aria-label="Permalink to &quot;B+Tree&quot;">​</a></h4><p>以一颗最大度数（max-degree）为4（4阶）的b+tree为例</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220410101649402.png" alt="image-20220410101649402" style="zoom:67%;"><p>相对于B-Tree区别:</p><p>①. 所有的数据都会出现在叶子节点</p><p>②. 叶子节点形成一个单向链表</p><p>MySQL索引数据结构对经典的B+Tree进行了优化。在原B+Tree的基础上，增加一个指向相邻叶子节点的链表指针，就形成了带有顺序指针的B+Tree，提高区间访问的性能。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220410101748106.png" alt="image-20220410101748106" style="zoom:67%;"><h4 id="hash" tabindex="-1">Hash <a class="header-anchor" href="#hash" aria-label="Permalink to &quot;Hash&quot;">​</a></h4><blockquote><ul><li>哈希索引就是采用一定的hash算法，将键值换算成新的hash值，映射到对应的槽位上，然后存储在hash表中。</li><li>如果两个(或多个)键值，映射到一个相同的槽位上，他们就产生了hash冲突（也称为hash碰撞），可以通过链表来解决。</li></ul></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220122224028505.png" alt="image-20220122224028505" style="zoom:80%;"><blockquote><ul><li>Hash索引只能用于对等比较(=，in)，不支持范围查询（between，&gt;，&lt; ，...）</li><li>无法利用索引完成排序操作</li><li>查询效率高，通常只需要一次检索就可以了，效率通常要高于B+tree索引</li></ul></blockquote><h2 id="索引分类⭐" tabindex="-1">索引分类⭐ <a class="header-anchor" href="#索引分类⭐" aria-label="Permalink to &quot;索引分类⭐&quot;">​</a></h2><h3 id="索引分类⭐-1" tabindex="-1">索引分类⭐ <a class="header-anchor" href="#索引分类⭐-1" aria-label="Permalink to &quot;索引分类⭐&quot;">​</a></h3><p>MySQL的索引包括<code>普通索引</code>、<code>唯一性索引</code>、<code>全文索引</code>、<code>单列索引</code>、<code>多列索引</code>和<code>空间索引</code>等。</p><p>从 <strong>功能逻辑</strong>上说，索引主要有 4 种，分别是<code>普通索引</code>、<code>唯一索引</code>、<code>主键索引</code>、<code>全文索引</code>。</p><p>按照 <strong>物理实现方式</strong> ，索引可以分为 2 种：<code>聚簇索引</code>和<code>非聚簇索引</code>。</p><p>按照 <strong>作用字段个数</strong> 进行划分，分成<code>单列索引</code>和<code>联合索引</code>。</p><h3 id="索引特点" tabindex="-1">索引特点 <a class="header-anchor" href="#索引特点" aria-label="Permalink to &quot;索引特点&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209202257099.png" alt="image-20220920225711009" style="zoom:80%;"><h3 id="索引详解" tabindex="-1">索引详解 <a class="header-anchor" href="#索引详解" aria-label="Permalink to &quot;索引详解&quot;">​</a></h3><blockquote><p><strong>B+tree 索引</strong>：B+tree 索引是 MySQL 默认使用的一种索引类型，适用于查找值相等的情况。B+tree 索引是一种平衡树结构，可以支持快速的查找、插入、删除操作，适合于经常变化的数据。</p></blockquote><blockquote><p><strong>哈希索引</strong>：哈希索引是将数据的哈希值作为索引存储的一种索引类型，适用于等值查询操作。哈希索引在数据量大的情况下性能非常好，但是不支持范围查询操作。</p></blockquote><blockquote><p><strong>全文索引</strong>：全文索引可以对文本内容进行搜索，适用于全文检索场景，比如博客、新闻、论坛等。MySQL 提供了 MyISAM 存储引擎中的全文索引，以及 InnoDB 存储引擎中的全文搜索插件。</p></blockquote><blockquote><p><strong>空间索引</strong>：空间索引可以用来处理具有空间数据的表，如经纬度等。MySQL 支持使用 GIS 功能进行空间索引的创建和查询。</p></blockquote><blockquote><p><strong>前缀索引</strong>：前缀索引是一种特殊的 B+tree 索引，只存储列值的前缀，而不是整个列值。前缀索引可以减小索引的存储空间，但是查询性能会受到影响。</p></blockquote><blockquote><p><strong>组合索引</strong>：组合索引是将多个列的值组合起来创建的一种索引，可以提高查询性能，减少索引数量。但是组合索引的列顺序需要注意，需要根据实际查询情况来决定。</p></blockquote><blockquote><p><strong>唯一索引</strong>：唯一索引是一种 B-tree 索引，用于保证列的唯一性。当在某列上创建唯一索引后，该列将不允许出现重复的值。</p></blockquote><blockquote><p><strong>主键索引</strong>：主键索引是一种唯一索引，用于标识表中的唯一记录。主键索引可以加速表的查询操作，通常在表创建时就应该定义好。</p></blockquote><h3 id="索引存储形式" tabindex="-1">索引存储形式 <a class="header-anchor" href="#索引存储形式" aria-label="Permalink to &quot;索引存储形式&quot;">​</a></h3><p>在InnoDB存储引擎中，根据索引的存储形式，又可以分为以下两种：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209202258756.png" alt="image-20220920225806673" style="zoom:80%;"><h4 id="聚集索引" tabindex="-1">聚集索引 <a class="header-anchor" href="#聚集索引" aria-label="Permalink to &quot;聚集索引&quot;">​</a></h4><blockquote><p>聚集索引是一种特殊的索引类型，<strong>它的叶子节点保存了整张表的数据行。当你定义一个主键或唯一索引时，MySQL 会默认创建一个聚集索</strong>引。<strong>如果没有显式地指定主键或唯一索引，MySQL 可能会隐式地创建一个包含所有列的隐藏聚集索引</strong>。</p></blockquote><blockquote><p>聚集索引的主要特点是它决定了数据的物理存储方式。<strong>因为聚集索引的叶子节点保存了整张表的数据行，所以聚集索引可以直接通过索引来获取数据，不需要再回表查询数据</strong>。</p></blockquote><h4 id="二级索引" tabindex="-1">二级索引 <a class="header-anchor" href="#二级索引" aria-label="Permalink to &quot;二级索引&quot;">​</a></h4><blockquote><p><strong>二级索引（又称为非聚集索引）是除了聚集索引之外的索引类型，它的叶子节点不包含数据行，而是包含一个指向数据行的指针</strong>。<strong>当你定义一个普通索引时，MySQL 会创建一个二级索引</strong>。</p></blockquote><blockquote><p>使用二级索引查询数据时，需要先通过索引查找到相应的数据行指针，再通过指针回表查询数据。<strong>因为二级索引需要回表查询数据，所以相比于聚集索引，它的查询性能稍差</strong>。</p></blockquote><blockquote><p>需要注意的是**，一个表可以有多个二级索引，但只能有一个聚集索引。并且在某些情况下，二级索引查询时也可以避免回表操作，例如覆盖索引查询或者使用索引的查询优化器**。</p></blockquote><h2 id="聚集索引分析⭐" tabindex="-1">聚集索引分析⭐ <a class="header-anchor" href="#聚集索引分析⭐" aria-label="Permalink to &quot;聚集索引分析⭐&quot;">​</a></h2><h3 id="聚集索引选取规则" tabindex="-1">聚集索引选取规则 <a class="header-anchor" href="#聚集索引选取规则" aria-label="Permalink to &quot;聚集索引选取规则&quot;">​</a></h3><blockquote><ul><li>如果存在主键，主键索引就是聚集索引</li><li>如果不存在主键，将使用第一个唯一索引作为聚集索引</li><li>如果表没有主键，或没有合适的唯一索引，则Innodb会自动生成一个rowid作为隐藏的聚集索引</li></ul></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220122224751133.png" alt="image-20220122224751133" style="zoom:80%;"><p>聚集索引的叶子节点下挂的是这一行的数据 。</p><p>二级索引的叶子节点下挂的是该字段值对应的主键值。</p><h3 id="sql查找流程" tabindex="-1">SQL查找流程 <a class="header-anchor" href="#sql查找流程" aria-label="Permalink to &quot;SQL查找流程&quot;">​</a></h3><p>接下来，我们来分析一下，当我们执行如下的SQL语句时，具体的查找过程是什么样子的。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206181449534.png" alt="image-20220618144947406" style="zoom:67%;"><p>具体过程如下:</p><blockquote><ul><li>由于是根据name字段进行查询，所以先根据name=&#39;Arm&#39;到name字段的二级索引中进行匹配查找。但是在二级索引中 只能查找到 Arm 对应的主键值 10。</li><li>由于查询返回的数据是*，所以此时，还需要根据主键值10，到聚集索引中查找10对应的记录，最终找到10对应的行row。</li><li>最终拿到这一行的数据，直接返回即可。上面过程经历了回表查询</li></ul></blockquote><h3 id="哪个sql执行效率高" tabindex="-1">哪个SQL执行效率高 <a class="header-anchor" href="#哪个sql执行效率高" aria-label="Permalink to &quot;哪个SQL执行效率高&quot;">​</a></h3><blockquote><p>思考题：以下两条SQL语句，那个执行效率高? 为什么?</p><p>A. select * from user where id = 10 ;</p><p>B. select * from user where name = &#39;Arm&#39; ;</p><p>备注: id为主键，name字段创建的有索引；</p><p>解答：A 语句的执行性能要高于B 语句。因为A语句直接走聚集索引，直接返回数据。 而B语句需要先查询name字段的二级索引，然后再查询聚集索引，也就是需要进行回表查询。</p></blockquote><h3 id="innodb主键索引的b-tree高度" tabindex="-1">InnoDB主键索引的B+tree高度 <a class="header-anchor" href="#innodb主键索引的b-tree高度" aria-label="Permalink to &quot;InnoDB主键索引的B+tree高度&quot;">​</a></h3><blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206181451707.png" alt="image-20220618145149590" style="zoom:67%;"><p>假设:</p><p>一行数据大小为1k，一页中可以存储16行这样的数据。InnoDB的指针占用6个字节的空间，主键即使为bigint，占</p><p>用字节数为8。高度为2：n * 8 + (n + 1) * 6 = 16*1024 , 算出n约为 1170。1171* 16 = 18736</p><p>也就是说，如果树的高度为2，则可以存储 18000 多条记录。</p><p>高度为3：1171 * 1171 * 16 = 21939856</p><p>也就是说，如果树的高度为3，则可以存储 2200w 左右的记录。</p></blockquote><h2 id="索引语法⭐" tabindex="-1">索引语法⭐ <a class="header-anchor" href="#索引语法⭐" aria-label="Permalink to &quot;索引语法⭐&quot;">​</a></h2><h3 id="基本语法" tabindex="-1">基本语法 <a class="header-anchor" href="#基本语法" aria-label="Permalink to &quot;基本语法&quot;">​</a></h3><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 创建索引</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> [unique、fulltext、或不写] </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> index_name </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> 表名(字段名);</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 查看索引</span></span>
<span class="line"><span style="color:#A6ACCD;">show </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> 表名;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 删除索引</span></span>
<span class="line"><span style="color:#F78C6C;">drop</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> 索引名 </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> 表名;</span></span></code></pre></div><h3 id="具体示例⭐⭐" tabindex="-1">具体示例⭐⭐ <a class="header-anchor" href="#具体示例⭐⭐" aria-label="Permalink to &quot;具体示例⭐⭐&quot;">​</a></h3><h4 id="创建索引" tabindex="-1">创建索引 <a class="header-anchor" href="#创建索引" aria-label="Permalink to &quot;创建索引&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202302281915907.png" alt="image-20230228191534755" style="zoom:80%;"><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 创建索引</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 1、name为姓名字段，该字段可能重复，为该字段创建索引</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_user_name</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> tb_user(</span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 2、phone字段是手机，要求非空且唯一，为该字段创建唯一索引</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">unique index</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_user_phone</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> tb_user(phone);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 3、为profession, age,status创建联合索引(组合索引)：顺序很重要</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_user_pro_age_sta</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> tb_user(profession, age,</span><span style="color:#F78C6C;">status</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 4、为email建立普通索引</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_user_email</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> tb_user(email);</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209210812433.png" alt="image-20220921081238322" style="zoom:80%;"><h4 id="查看索引" tabindex="-1">查看索引 <a class="header-anchor" href="#查看索引" aria-label="Permalink to &quot;查看索引&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 查看索引</span></span>
<span class="line"><span style="color:#A6ACCD;">show </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> account;</span></span>
<span class="line"><span style="color:#A6ACCD;">show </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">admin</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><h4 id="删除索引" tabindex="-1">删除索引 <a class="header-anchor" href="#删除索引" aria-label="Permalink to &quot;删除索引&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 删除索引</span></span>
<span class="line"><span style="color:#F78C6C;">drop</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> idx_user_email </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> tb_user;</span></span></code></pre></div><h3 id="验证索引执行效率" tabindex="-1">验证索引执行效率 <a class="header-anchor" href="#验证索引执行效率" aria-label="Permalink to &quot;验证索引执行效率&quot;">​</a></h3><h4 id="批量导入数据" tabindex="-1">批量导入数据 <a class="header-anchor" href="#批量导入数据" aria-label="Permalink to &quot;批量导入数据&quot;">​</a></h4><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">load data local infile </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">/root/sql/tb_sku1.sql</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> into table `tb_sku` fields terminated by </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> lines terminated by </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">\n</span><span style="color:#89DDFF;">&#39;</span><span style="color:#89DDFF;">;</span></span></code></pre></div><blockquote><ul><li>由于1000w的数据量较大 , 如果直接加载1000w , 会非常耗费CPU及内存 ;</li><li>已经拆分为5个部分 , 每一个部分为200w数据 , load 5次即可 ;</li></ul></blockquote><h4 id="测试执行效率" tabindex="-1">测试执行效率 <a class="header-anchor" href="#测试执行效率" aria-label="Permalink to &quot;测试执行效率&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 1、在未建立索引之前，执行如下SQL语句，查看SQL的耗时。执行时间443ms</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> username </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">eyMLhSWXIS99046</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 2、针对字段创建索引</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_user</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> tb_user(username);</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 3、然后再次执行相同的SQL语句，再次查看SQL的耗时。执行时间65ms</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> username </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">eyMLhSWXIS99046</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><h2 id="最左前缀法则⭐" tabindex="-1">最左前缀法则⭐ <a class="header-anchor" href="#最左前缀法则⭐" aria-label="Permalink to &quot;最左前缀法则⭐&quot;">​</a></h2><h3 id="什么是最左前缀" tabindex="-1">什么是最左前缀 <a class="header-anchor" href="#什么是最左前缀" aria-label="Permalink to &quot;什么是最左前缀&quot;">​</a></h3><blockquote><p>如果索引使用了联合索引，要遵循最左前缀，是指查询从索引最左列开始，并且不跳过索引中的列</p><p>如果跳过了某一列，索引将部分失效(后面的字段索引失效)</p><p>即最左优先，在检索数据时从联合索引的最左边开始匹配，直到遇到范围查询（如：&gt; 、&lt; 、between、like等）</p></blockquote><h3 id="最左前缀测试" tabindex="-1">最左前缀测试 <a class="header-anchor" href="#最左前缀测试" aria-label="Permalink to &quot;最左前缀测试&quot;">​</a></h3><p>以 tb_user 表为例，我们先来查看一下之前 tb_user 表所创建的索引。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 为profession, age,status创建联合索引(组合索引)：顺序很重要</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_user_pro_age_sta</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> tb_user(profession, age,</span><span style="color:#F78C6C;">status</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">show indexes </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209210949547.png" alt="image-20220921094940472" style="zoom:80%;"><p>在 tb_user 表中，有一个联合索引，这个联合索引涉及到三个字段，顺序分别为：profession，age，status。</p><blockquote><p>对于最左前缀法则指的是，查询时，最左变的列，也就是profession必须存在，否则索引全部失效。而且中间不能跳过某一列，否则该列后面的字段索引将失效。 接下来，我们来演示几组案例，看一下具体的执行计划：</p></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> profession </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">软件工程</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">and</span><span style="color:#A6ACCD;"> age </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">31</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">and</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">status</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">0</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">explain  </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> profession </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">软件工程</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">and</span><span style="color:#A6ACCD;"> age </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">31</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> profession </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">软件工程</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211005011.png" alt="image-20220921100548935" style="zoom:80%;"><blockquote><p>以上的这三组测试中，我们发现只要联合索引最左边的字段 profession存在，索引就会生效，只不过索引的长度不同。 而且由以上三组测试，我们也可以推测出profession字段索引长度为47、age字段索引长度为2、status字段索引长度为5。</p></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 索引完全失效</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">status</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">0</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- status不再走索引</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> profession </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">软件工程</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">and</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">status</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">0</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211008975.png" alt="image-20220921100833899" style="zoom:80%;"><blockquote><p>而通过上面的这两组测试，我们也可以看到索引并未生效，原因是因为不满足最左前缀法则，联合索引最左边的列profession不存在。</p></blockquote><h3 id="注意事项⭐" tabindex="-1">注意事项⭐ <a class="header-anchor" href="#注意事项⭐" aria-label="Permalink to &quot;注意事项⭐&quot;">​</a></h3><blockquote><p>当执行SQL语句: explain select * from tb_user where age = 31 and status = &#39;0&#39; and profession = &#39;软件工程&#39;； 时，是否满足最左前缀法则，走不走上述的联合索引，索引长度？</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211014126.png" alt="image-20220921101409050" style="zoom:80%;"><p>可以看到，是完全满足最左前缀法则的，索引长度54，联合索引是生效的。注意 ： 最左前缀法则中指的最左边的列，</p><p>是指在查询时，联合索引的最左边的字段(即是第一个字段)必须存在，<strong>与我们编写SQL时，条件编写的先后顺序无关。</strong></p><h2 id="索引失效场景⭐⭐" tabindex="-1">索引失效场景⭐⭐ <a class="header-anchor" href="#索引失效场景⭐⭐" aria-label="Permalink to &quot;索引失效场景⭐⭐&quot;">​</a></h2><p><a href="https://mp.weixin.qq.com/s?__biz=MzU1NTkwODE4Mw==&amp;mid=2247503132&amp;idx=1&amp;sn=6f4616f1b37f67108164feaa69e06c69&amp;chksm=fbcfa024ccb82932a069f88e39b64c1db794b594e30c0bfc62bc9156c922f4ec1ea92f075e53&amp;mpshare=1&amp;scene=23&amp;srcid=0215RfZ7r2bI3fnkyFAg7Hod&amp;sharer_sharetime=1676426872108&amp;sharer_shareid=29b8a04db1dbd975e3bf4e9f47e7ac67#rd" target="_blank" rel="noreferrer">MySQL 索引失效的 15 种场景！还没开搞，等复习MySQL时候再搞他</a></p><p><a href="https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==&amp;mid=2247497533&amp;idx=2&amp;sn=617af9579748ed5edddb3efa79ab9346&amp;chksm=fc2c4b35cb5bc22368f5b804b87a44ba432048470f25d140231a30542b300c51d855a01f83cc&amp;mpshare=1&amp;scene=23&amp;srcid=04151rD4gvtEPZaiM2Lv59QR&amp;sharer_sharetime=1650024521520&amp;sharer_shareid=29b8a04db1dbd975e3bf4e9f47e7ac67#rd" target="_blank" rel="noreferrer">聊聊索引失效的 10 种场景，太坑了！ (qq.com)</a></p><ul><li>明明在某个字段上加了索引，但实际上并没有生效。</li><li>索引有时候生效了，有时候没有生效。</li></ul><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.5/202205081308094.png" alt="image-20220508130834995" style="zoom:67%;"><h3 id="准备工作" tabindex="-1">准备工作 <a class="header-anchor" href="#准备工作" aria-label="Permalink to &quot;准备工作&quot;">​</a></h3><h4 id="创建表结构" tabindex="-1">创建表结构 <a class="header-anchor" href="#创建表结构" aria-label="Permalink to &quot;创建表结构&quot;">​</a></h4><p>为了逐项验证索引的使用情况，我们先准备一张表t_user：</p><p>创建一张user表，表中包含：<code>id</code>、<code>code</code>、<code>age</code>、<code>name</code>和<code>height</code>字段。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">table</span><span style="color:#A6ACCD;"> `</span><span style="color:#82AAFF;">t_user</span><span style="color:#A6ACCD;">` (</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">11</span><span style="color:#A6ACCD;">) unsigned </span><span style="color:#F78C6C;">not null</span><span style="color:#A6ACCD;"> auto_increment comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">id_no</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">18</span><span style="color:#A6ACCD;">)  </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">身份编号</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">username</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">32</span><span style="color:#A6ACCD;">)  </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">用户名</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">age</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">11</span><span style="color:#A6ACCD;">) </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">年龄</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">create_time</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">datetime</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> current_timestamp comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">创建时间</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#C792EA;">primary key</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">),</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#F78C6C;">key</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">union_idx</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">id_no</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">username</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">age</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">),</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#F78C6C;">key</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">create_time_idx</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">create_time</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">);</span></span></code></pre></div><p>此外，还创建了三个索引：</p><ul><li><code>id</code>：数据库的主键</li><li><code>union_idx</code>：<strong>由<code>id_no</code>,<code>username</code>,<code>age</code>三个字段组成的联合索引</strong>。</li><li><code>create_time_idx</code>：普通索引</li></ul><h4 id="插入数据" tabindex="-1">插入数据 <a class="header-anchor" href="#插入数据" aria-label="Permalink to &quot;插入数据&quot;">​</a></h4><p>为了方便给大家做演示，我特意向user表中插入了3条数据：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">insert into</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">t_user</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">values</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">1001</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">tom1</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">11</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">2022-02-27 09:04:23</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"><span style="color:#F78C6C;">insert into</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">t_user</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">values</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">1002</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">tom2</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">12</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">2022-02-26 09:04:23</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"><span style="color:#F78C6C;">insert into</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">t_user</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">values</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">1003</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">tom3</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">13</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">2022-02-25 09:04:23</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"><span style="color:#F78C6C;">insert into</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">t_user</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">values</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">1004</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">tom4</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">14</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">2023-02-25 09:04:23</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">);</span></span></code></pre></div><h4 id="存储过程" tabindex="-1">存储过程 <a class="header-anchor" href="#存储过程" aria-label="Permalink to &quot;存储过程&quot;">​</a></h4><p>除了基础数据，还有一条存储过程及其调用的SQL，方便批量插入数据，用来验证数据比较多的场景：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 删除历史存储过程</span></span>
<span class="line"><span style="color:#F78C6C;">drop</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">procedure</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">exists</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">insert_t_user</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 创建存储过程</span></span>
<span class="line"><span style="color:#A6ACCD;">delimiter $</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">procedure</span><span style="color:#A6ACCD;"> insert_t_user(</span><span style="color:#F78C6C;">in</span><span style="color:#A6ACCD;"> limit_num </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#F78C6C;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">declare</span><span style="color:#A6ACCD;"> i </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">declare</span><span style="color:#A6ACCD;"> id_no </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">18</span><span style="color:#A6ACCD;">) ;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">declare</span><span style="color:#A6ACCD;"> username </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">32</span><span style="color:#A6ACCD;">) ;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">declare</span><span style="color:#A6ACCD;"> age </span><span style="color:#F78C6C;">tinyint</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">while</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">&lt;</span><span style="color:#A6ACCD;"> limit_num do</span></span>
<span class="line"><span style="color:#89DDFF;">        </span><span style="color:#676E95;font-style:italic;">-- 这边报错不用管</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#F78C6C;">set</span><span style="color:#A6ACCD;"> id_no </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">concat</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">no</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, i);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#F78C6C;">set</span><span style="color:#A6ACCD;"> username </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">concat</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">tom</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">,i);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#F78C6C;">set</span><span style="color:#A6ACCD;"> age </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">floor</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">rand</span><span style="color:#A6ACCD;">()</span><span style="color:#89DDFF;">*</span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#F78C6C;">insert into</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">t_user</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">values</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">, id_no, username, age, </span><span style="color:#F78C6C;">now</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">        </span><span style="color:#F78C6C;">set</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">end</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">while</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F78C6C;">end</span><span style="color:#A6ACCD;"> $</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 调用存储过程</span></span>
<span class="line"><span style="color:#F78C6C;">call</span><span style="color:#A6ACCD;"> insert_t_user(</span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">);</span></span></code></pre></div><h4 id="查看数据库版本" tabindex="-1">查看数据库版本 <a class="header-anchor" href="#查看数据库版本" aria-label="Permalink to &quot;查看数据库版本&quot;">​</a></h4><p>为了防止以后出现不必要的误会，在这里有必要查一下当前数据库的版本。不说版本就直接给结论，是耍流氓</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">version</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>查出当前的mysql版本号为：<code>8.0.28</code></p><h4 id="查看索引-1" tabindex="-1">查看索引 <a class="header-anchor" href="#查看索引-1" aria-label="Permalink to &quot;查看索引&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show indexes </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011000768.png" alt="image-20230301100042657" style="zoom:80%;"><h4 id="执行示例" tabindex="-1">执行示例 <a class="header-anchor" href="#执行示例" aria-label="Permalink to &quot;执行示例&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>执行结果：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011006400.png" alt="image-20230301100634279" style="zoom:80%;"><p>可以看到上述SQL语句使用了主键索引（PRIMARY），<code>key_len</code>为4；其中<code>key_len</code>的含义为：表示索引使用的字节数，根据这个值可以判断索引的使用情况，特别是在组合索引的时候，判断该索引有多少部分被使用到非常重要。</p><p>做好以上数据及知识的准备，下面就开始讲解具体索引失效的实例了。</p><h3 id="联合索引不满足最左匹配原则" tabindex="-1">联合索引不满足最左匹配原则 <a class="header-anchor" href="#联合索引不满足最左匹配原则" aria-label="Permalink to &quot;联合索引不满足最左匹配原则&quot;">​</a></h3><blockquote><p><strong>在联合索引的场景下，查询条件不满足最左匹配原则</strong>。</p></blockquote><blockquote><p>联合索引遵从最左匹配原则，顾名思义，<strong>在联合索引中，最左侧的字段优先匹配</strong>。因此，在创建联合索引时，where子句中使用最频繁的字段放在组合索引的最左侧。</p></blockquote><blockquote><p>而在查询时，要想让查询条件走索引，则需满足：最左边的字段要出现在查询条件中。</p><p>实例中，<code>union_idx</code>联合索引组成：</p></blockquote><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">KEY `union_idx` (`id_no`,`username`,`age`)</span></span></code></pre></div><p>最左边的字段为id_no，一般情况下，只要保证id_no出现在查询条件中，则会走该联合索引。</p><p><strong>示例一</strong>：</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain select * from t_user where id_no = &#39;1002&#39;;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011008543.png" alt="image-20230301100807439" style="zoom:80%;"><p>通过explain执行结果可以看出，上述SQL语句走了<code>union_idx</code>这条索引。这里再普及一下key_len的计算：</p><ul><li><code>id_no</code> 类型为varchar(18)，字符集为utf8mb4_bin，也就是使用4个字节来表示一个完整的UTF-8。此时，key_len = 18* 4 = 72；</li><li>由于该字段类型varchar为变长数据类型，需要再额外添加2个字节。此时，key_len = 72 + 2 = 74；</li><li>由于该字段运行为NULL（default NULL），需要再添加1个字节。此时，key_len = 74 + 1 = 75；</li></ul><p>上面演示了key_len一种情况的计算过程，后续不再进行逐一推演，知道基本组成和原理即可</p><p><strong>示例二</strong>：</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain select * from t_user where id_no = &#39;1002&#39; and username = &#39;Tom2&#39;;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011008533.png" alt="image-20230301100849431" style="zoom:80%;"><p>很显然，依旧走了<code>union_idx</code>索引，根据上面key_len的分析，大胆猜测，在使用索引时，不仅使用了<code>id_no</code>列，还使用了<code>username</code>列。</p><p><strong>示例三</strong>：</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain select * from t_user where id_no = &#39;1002&#39; and age = 12;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011009335.png" alt="image-20230301100914231" style="zoom:80%;"><p>走了<code>union_idx</code>索引，但跟示例一一样，只用到了<code>id_no</code>列。</p><p>当然，还有三列都在查询条件中的情况，就不再举例了。上面都是走索引的正向例子，也就是满足<code>最左匹配原则</code>的例子，下面来看看，不满足该原则的反向例子。</p><p><strong>反向示例</strong>：</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain select * from t_user where username = &#39;Tom2&#39; and age = 12;</span></span></code></pre></div><p>explain结果：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011009412.png" alt="image-20230301100948302" style="zoom:80%;"><p>此时，可以看到未走任何索引，也就是说索引失效了。同样的，下面只要没出现最左条件的组合，索引也是失效的</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> age </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">12</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> username </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">Tom2</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><h3 id="查询所有列" tabindex="-1">查询所有列 <a class="header-anchor" href="#查询所有列" aria-label="Permalink to &quot;查询所有列&quot;">​</a></h3><blockquote><p><strong>在联合索引下，尽量使用明确的查询列来趋向于走覆盖索引</strong>；</p></blockquote><p>在《阿里巴巴开发手册》的<strong>ORM映射</strong>章节中有一条【强制】的规范：</p><blockquote><p>【强制】在表查询中，一律不要使用 * 作为查询的字段列表，需要哪些字段必须明确写明。说明:1)增加查询分析器解析成本。2)增减字段容易与 resultMap 配置不一致。3)无用字段增加网络 消耗，尤其是 text 类型的字段。</p></blockquote><blockquote><p>虽然在规范手册中没有提到索引方面的问题，但禁止使用<code>select *</code> 语句可能会带来的附带好处就是：<strong>某些情况下可以走<code>覆盖索引</code></strong>。</p></blockquote><blockquote><p>比如，在上面的联合索引中，如果查询条件是age或username，当使用了<code>select *</code> ，肯定是不会走索引的。</p></blockquote><blockquote><p>但如果希望根据username查询出id_no、username、age这三个结果（均为索引字段），明确查询结果字段，是可以走<code>覆盖索引</code>的：</p></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id_no, username, age </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> username </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">Tom2</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id_no, username, age </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> age </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">12</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011011225.png" alt="image-20230301101124111" style="zoom:80%;"><p>无论查询条件是<code>username</code>还是<code>age</code>，都走了索引，根据key_len可以看出使用了索引的所有列。</p><blockquote><p>这一条不走索引的情况属于优化项，如果业务场景满足，则进来促使SQL语句走索引。至于阿里巴巴开发手册中的规范，只不过是两者撞到一起了，规范本身并不是为这条索引规则而定的。</p></blockquote><h3 id="索引列参与运算" tabindex="-1">索引列参与运算 <a class="header-anchor" href="#索引列参与运算" aria-label="Permalink to &quot;索引列参与运算&quot;">​</a></h3><blockquote><p><strong>索引列参与了运算，会导致全表扫描，索引失效</strong>。</p></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;"> ;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011013502.png" alt="image-20230301101319398" style="zoom:80%;"><p>可以看到，即便id列有索引，由于进行了计算处理，导致无法正常走索引。</p><blockquote><p>针对这种情况，其实不单单是索引的问题，还会增加数据库的计算负担。就以上述SQL语句为例，数据库需要全表扫描出所有的id字段值，然后对其计算，计算之后再与参数值进行比较。如果每次执行都经历上述步骤，性能损耗可想而知。建议方式：先在内存中进行计算好预期的值，或者在SQL语句条件的右侧进行参数值的计算。</p></blockquote><p>针对上述示例的优化如下：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 内存计算，得知要查询的id为1</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> ;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 参数侧计算</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> ;</span></span></code></pre></div><h3 id="索引列用了函数" tabindex="-1">索引列用了函数 <a class="header-anchor" href="#索引列用了函数" aria-label="Permalink to &quot;索引列用了函数&quot;">​</a></h3><blockquote><p><strong>索引列参与了函数处理，会导致全表扫描，索引失效</strong>。解决方案：<strong>可考虑先通过内存计算或其他方式减少数据库来进行内容的处理</strong>。</p></blockquote><p>有时候我们在某条sql语句的查询条件中，需要使用函数，比如：截取某个字段的长度。</p><p>假如现在有个需求：想查出所有身高是17开头的人，如果sql语句写成这样：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user  </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> height</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">17</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>该sql语句确实用到了普通索引：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211645589.png" alt="image-20220921164523480" style="zoom:80%;"><p>但该sql语句肯定是有问题的，因为它只能查出身高正好等于17的，但对于174这种情况，它没办法查出来。</p><p>为了满足上面的要求，我们需要把sql语句稍稍改造了一下：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> user  </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> SUBSTR(height,</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">)</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">17</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>这时需要用到<code>SUBSTR</code>函数，用它截取了height字段的前面两位字符，从第一个字符开始。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211645250.png" alt="image-20220921164556137" style="zoom:80%;"><p>你有没有发现，在使用该函数之后，该sql语句竟然走了全表扫描，索引失效了。</p><h3 id="类型隐式转换" tabindex="-1">类型隐式转换 <a class="header-anchor" href="#类型隐式转换" aria-label="Permalink to &quot;类型隐式转换&quot;">​</a></h3><blockquote><p><strong>参数类型与字段类型不匹配，导致类型发生了隐式转换，索引失效</strong>。</p></blockquote><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain select * from t_user where id_no = 1002;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011019668.png" alt="image-20230301101942538" style="zoom:67%;"><p><code>id_no</code>字段类型为varchar，但在SQL语句中使用了int类型，导致全表扫描。</p><p>出现索引失效的原因是：varchar和int是两个种不同的类型。</p><p>解决方案就是将参数<code>1002</code>添加上单引号或双引号。</p><p>这种情况还有一个特例，如果字段类型为int类型，而查询条件添加了单引号或双引号，则Mysql会参数转化为int类型，虽然使用了单引号或双引号：</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain select * from t_user where id = &#39;2&#39;;</span></span></code></pre></div><p>上述语句是依旧会走索引的。</p><h3 id="like左边包含" tabindex="-1">like左边包含% <a class="header-anchor" href="#like左边包含" aria-label="Permalink to &quot;like左边包含%&quot;">​</a></h3><blockquote><p><strong>当<code>like</code>语句中的<code>%</code>，出现在查询条件的左边时，索引会失效。</strong></p></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id_no </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%00%</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011017829.png" alt="image-20230301101737702" style="zoom:80%;"><p>针对<code>like</code>的使用非常频繁，但使用不当往往会导致不走索引。常见的like使用方式有：</p><ul><li>方式一：like &#39;%abc&#39;；</li><li>方式二：like &#39;abc%&#39;；</li><li>方式三：like &#39;%abc%&#39;；</li></ul><blockquote><p>其中方式一和方式三，由于占位符出现在首部，导致无法走索引。这种情况不做索引的原因很容易理解，索引本身就相当于目录，从左到右逐个排序。而条件的左侧使用了占位符，导致无法按照正常的目录进行匹配，导致索引失效就很正常了。</p></blockquote><blockquote><p>那么，为什么会出现这种现象呢？ 答：其实很好理解，索引就像字典中的目录。一般目录是按字母或者拼音从小到大，从左到右排序，是有顺序的。</p></blockquote><blockquote><p>我们在查目录时，通常会先从左边第一个字母进行匹对，如果相同，再匹对左边第二个字母，如果再相同匹对其他的字母，以此类推。通过这种方式我们能快速锁定一个具体的目录，或者缩小目录的范围。但如果你硬要跟目录的设计反着来，先从字典目录右边匹配第一个字母，这画面你可以自行脑补一下，你眼中可能只剩下绝望了，哈哈。</p></blockquote><h3 id="两列做比较" tabindex="-1">两列做比较 <a class="header-anchor" href="#两列做比较" aria-label="Permalink to &quot;两列做比较&quot;">​</a></h3><blockquote><p><strong>两列数据做比较，即便两列都创建了索引，索引也会失效</strong>。</p></blockquote><p>如果两个列数据都有索引，但在查询条件中对两列数据进行了对比操作，则会导致索引失效。</p><p>这里举个不恰当的示例，比如age小于id这样的两列（真实场景可能是两列同维度的数据比较，这里迁就现有表结构）：</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain select * from t_user where id &gt; age;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011031838.png" alt="image-20230301103139708" style="zoom:80%;"><p>这里虽然id有索引，age也可以创建索引，但当两列做比较时，索引还是会失效的。</p><h3 id="or" tabindex="-1">or <a class="header-anchor" href="#or" aria-label="Permalink to &quot;or&quot;">​</a></h3><blockquote><p><strong>查询条件使用or关键字，其中一个字段没有创建索引，则会导致整个查询语句索引失效；or两边为“&gt;”和“&lt;”范围查询时，索引失效</strong>。</p></blockquote><p>我们平时在写查询sql时，使用<code>or</code>关键字的场景非常多，但如果你稍不注意，就可能让已有的索引失效。</p><p>不信一起往下面看。某天你遇到这样一个需求：想查一下id=1或者height=175的用户。</p><p>你三下五除二就把sql写好了：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">or</span><span style="color:#A6ACCD;"> height</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">175</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211652232.png" alt="image-20220921165204115" style="zoom:80%;"><p>没错，这次确实走了索引，恭喜被你蒙对了，因为刚好id和height字段都建了索引。</p><p>但接下来的一个夜黑风高的晚上，需求改了：除了前面的查询条件之后，还想加一个address=&#39;成都&#39;。这还不简单</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">or</span><span style="color:#A6ACCD;"> height</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">175</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">or</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">address</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">成都</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211654409.png" alt="image-20220921165444303" style="zoom:80%;"><p>结果悲剧了，之前的索引都失效了。你可能一脸懵逼，为什么？我做了什么？</p><p>答：因为你最后加的address字段没有加索引，从而导致其他字段的索引都失效了。</p><blockquote><p>注意：如果使用了<code>or</code>关键字，那么它前面和后面的字段都要加索引，不然所有的索引都会失效，这是一个大坑。</p></blockquote><h3 id="不等于比较" tabindex="-1">不等于比较 <a class="header-anchor" href="#不等于比较" aria-label="Permalink to &quot;不等于比较&quot;">​</a></h3><blockquote><p><strong>查询条件使用不等进行比较时，需要慎重，普通索引会查询结果集占比较大时索引会失效</strong>。</p></blockquote><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain select * from t_user where id_no &lt;&gt; &#39;1002&#39;;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011029319.png" alt="image-20230301102958200" style="zoom:67%;"><p>当查询条件为字符串时，使用”&lt;&gt;“或”!=“作为条件查询，有可能不走索引，但也不全是。</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain select * from t_user where create_time != &#39;2022-02-27 09:56:42&#39;;</span></span></code></pre></div><p>上述SQL中，由于“2022-02-27 09:56:42”是存储过程在同一秒生成的，大量数据是这个时间。执行之后会发现，当查询结果集占比比较小时，会走索引，占比比较大时不会走索引。此处与结果集与总体的占比有关。</p><p>需要注意的是：上述语句如果是<code>id</code>进行不等操作，则正常走索引。</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain select * from t_user where id != 2;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011030972.png" alt="image-20230301103018867" style="zoom:80%;"><h3 id="is-not-null" tabindex="-1">is not null <a class="header-anchor" href="#is-not-null" aria-label="Permalink to &quot;is not null&quot;">​</a></h3><blockquote><p><strong>查询条件使用is null时正常走索引，使用is not null时，不走索引</strong>。</p></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id_no </span><span style="color:#F78C6C;">is not null</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011028590.png" alt="image-20230301102858485" style="zoom:80%;"><h3 id="not-in-not-exists" tabindex="-1">not in &amp; not exists <a class="header-anchor" href="#not-in-not-exists" aria-label="Permalink to &quot;not in &amp; not exists&quot;">​</a></h3><blockquote><p><strong>查询条件使用not in时，如果是主键则走索引，如果是普通索引，则索引失效</strong>。</p><p><strong>查询条件使用not exists时，索引失效</strong>。</p></blockquote><p>在日常中使用比较多的范围查询有in、exists、not in、not exists、between and等。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">in</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">3</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id_no </span><span style="color:#F78C6C;">in</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">1001</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">1002</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user u1 </span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">exists</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user u2 </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> u2.id  </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">and</span><span style="color:#A6ACCD;"> u2.id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> u1.id);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id_no </span><span style="color:#F78C6C;">between</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">1002</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">and</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">1003</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>上述四种语句执行时都会正常走索引，具体的explain结果就不再展示。主要看不走索引的情况：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id_no </span><span style="color:#F78C6C;">not</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">in</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">1002</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> , </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">1003</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">);</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011026431.png" alt="image-20230301102626326" style="zoom:80%;"><p>当使用<code>not in</code>时，不走索引？把条件列换成主键试试：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">not</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">in</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">3</span><span style="color:#A6ACCD;">);</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011026533.png" alt="image-20230301102655430" style="zoom:80%;"><p>如果是主键，则正常走索引。再来看看<code>not exists</code>：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user u1 </span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">not</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">exists</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user u2 </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> u2.id  </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">and</span><span style="color:#A6ACCD;"> u2.id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> u1.id);</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011027719.png" alt="image-20230301102742600" style="zoom:80%;"><p>当查询条件使用<code>not exists</code>时，不走索引。</p><h3 id="参数不同导致索引失效" tabindex="-1">参数不同导致索引失效 <a class="header-anchor" href="#参数不同导致索引失效" aria-label="Permalink to &quot;参数不同导致索引失效&quot;">​</a></h3><blockquote><p><strong>当查询条件为大于等于、in等范围查询时，根据查询结果占全表数据比例的不同，优化器有可能会放弃索引，进行全表扫描。</strong></p></blockquote><p>此时，如果你还未执行最开始创建的存储过程，建议你先执行一下存储过程，然后执行如下SQL：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> create_time </span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">2023-02-24 09:04:23</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>其中，时间是未来的时间，确保能够查到数据。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011022297.png" alt="image-20230301102253173" style="zoom:80%;"><p>可以看到，正常走索引。随后，我们将查询条件的参数换个日期：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> create_time </span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">2022-02-27 09:04:23</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011023298.png" alt="image-20230301102308173" style="zoom:80%;"><blockquote><p>此时，进行了全表扫描。这也是最开始提到的奇怪的现象。为什么同样的查询语句，只是查询的参数值不同，却会出现一个走索引，一个不走索引的情况呢？</p></blockquote><blockquote><p>答案很简单：<strong>上述索引失效是因为DBMS发现全表扫描比走索引效率更高，因此就放弃了走索引</strong>。</p></blockquote><blockquote><p>也就是说，当Mysql发现通过索引扫描的行记录数超过全表的10%-30%时，优化器可能会放弃走索引，自动变成全表扫描。某些场景下即便强制SQL语句走索引，也同样会失效。</p></blockquote><blockquote><p>类似的问题，在进行范围查询（比如&gt;、&lt; 、&gt;=、&lt;=、in等条件）时往往会出现上述情况，而上面提到的临界值根据场景不同也会有所不同。</p></blockquote><h3 id="order-by" tabindex="-1">order by <a class="header-anchor" href="#order-by" aria-label="Permalink to &quot;order by&quot;">​</a></h3><blockquote><p><strong>当查询条件涉及到order by、limit等条件时，是否走索引情况比较复杂，而且与MySQL版本有关，通常普通索引，如果未使用limit，则不会走索引。order by多个索引字段时，可能不会走索引。其他情况，建议在使用时进行expain验证。</strong></p></blockquote><p>在sql语句中，对查询结果进行排序是非常常见的需求，一般情况下我们用关键字：<code>order by</code>就能搞定。</p><p>但我始终觉得order by挺难用的，它跟<code>where</code>或者<code>limit</code>关键字有很多千丝万缕的联系，一不小心就会出问题。</p><h4 id="哪些情况走索引" tabindex="-1">哪些情况走索引？ <a class="header-anchor" href="#哪些情况走索引" aria-label="Permalink to &quot;哪些情况走索引？&quot;">​</a></h4><p>首先当然要温柔一点，一起看看order by的哪些情况可以走索引。</p><p>我之前说过，在code、age和name这3个字段上，已经建了联合索引：idx_code_age_name。</p><h5 id="满足最左匹配原则" tabindex="-1">满足最左匹配原则 <a class="header-anchor" href="#满足最左匹配原则" aria-label="Permalink to &quot;满足最左匹配原则&quot;">​</a></h5><p>order by后面的条件，也要遵循联合索引的最左匹配原则。具体有以下sql：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> user </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> code </span><span style="color:#F78C6C;">limit</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> user </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> code,age </span><span style="color:#F78C6C;">limit</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> user </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> code,age,</span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">limit</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>从图中看出这3条sql都能够正常走索引。</p><p>除了遵循最左匹配原则之外，有个非常关键的地方是，后面还是加了<code>limit</code>关键字，如果不加它索引会失效。</p><h5 id="配合where" tabindex="-1">配合where <a class="header-anchor" href="#配合where" aria-label="Permalink to &quot;配合where&quot;">​</a></h5><p>order by还能配合where一起遵循最左匹配原则。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> code</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">101</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> age;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211706100.png" alt="image-20220921170655982" style="zoom:80%;"><p>code是联合索引的第一个字段，在where中使用了，而age是联合索引的第二个字段，在order by中接着使用。</p><p>假如中间断层了，sql语句变成这样，执行结果会是什么呢？</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> code</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">101</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211708076.png" alt="image-20220921170841958" style="zoom:80%;"><blockquote><p>虽说name是联合索引的第三个字段，但根据最左匹配原则，该sql语句依然能走索引，因为最左边的第一个字段code，在where中使用了。只不过order by的时候，排序效率比较低，需要走一次<code>filesort</code>排序罢了。</p></blockquote><h5 id="相同的排序" tabindex="-1">相同的排序 <a class="header-anchor" href="#相同的排序" aria-label="Permalink to &quot;相同的排序&quot;">​</a></h5><p>order by后面如果包含了联合索引的多个排序字段，只要它们的排序规律是相同的（要么同时升序，要么同时降序），也可以走索引。具体sql如下：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> user </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> code </span><span style="color:#F78C6C;">desc</span><span style="color:#A6ACCD;">,age </span><span style="color:#F78C6C;">desc</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">limit</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>执行结果：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022/202204242100796.png" alt="image-20220424210001755" style="zoom:67%;"><p>该示例中order by后面的code和age字段都用了降序，所以依然走了索引。</p><h5 id="两者都有" tabindex="-1">两者都有 <a class="header-anchor" href="#两者都有" aria-label="Permalink to &quot;两者都有&quot;">​</a></h5><p>如果某个联合索引字段，在where和order by中都有，结果会怎么样？</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> code</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">101</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> code, </span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211710225.png" alt="image-20220921171029114" style="zoom:80%;"><p>code字段在where和order by中都有，对于这种情况，从图中的结果看出，还是能走了索引的。</p><h4 id="哪些情况不走索引" tabindex="-1">哪些情况不走索引？ <a class="header-anchor" href="#哪些情况不走索引" aria-label="Permalink to &quot;哪些情况不走索引？&quot;">​</a></h4><p>前面介绍的都是正面的用法，是为了让大家更容易接受下面反面的用法。</p><p>好了，接下来，重点聊聊order by的哪些情况下不走索引？</p><h5 id="没加where或limit" tabindex="-1">没加where或limit <a class="header-anchor" href="#没加where或limit" aria-label="Permalink to &quot;没加where或limit&quot;">​</a></h5><p>如果order by语句中没有加where或limit关键字，该sql语句将不会走索引。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> user </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> code, </span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211721086.png" alt="image-20220921172128976" style="zoom:80%;"><p>从图中看出索引真的失效了。</p><h5 id="对不同的索引做order-by" tabindex="-1">对不同的索引做order by <a class="header-anchor" href="#对不同的索引做order-by" aria-label="Permalink to &quot;对不同的索引做order by&quot;">​</a></h5><p>前面介绍的基本都是联合索引，这一个索引的情况。但如果对多个索引进行order by，结果会怎么样呢？</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> user </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> code, height </span><span style="color:#F78C6C;">limit</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211721086.png" alt="image-20220921172128976" style="zoom:80%;"><p>从图中看出索引也失效了。</p><h5 id="不满足最左匹配原则" tabindex="-1">不满足最左匹配原则 <a class="header-anchor" href="#不满足最左匹配原则" aria-label="Permalink to &quot;不满足最左匹配原则&quot;">​</a></h5><p>前面已经介绍过，order by如果满足最左匹配原则，还是会走索引。下面看看，不满足最左匹配原则的情况：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> user </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">limit</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211721086.png" alt="image-20220921172128976" style="zoom:80%;"><p>name字段是联合索引的第三个字段，从图中看出如果order by不满足最左匹配原则，确实不会走索引。</p><h5 id="不同的排序" tabindex="-1">不同的排序 <a class="header-anchor" href="#不同的排序" aria-label="Permalink to &quot;不同的排序&quot;">​</a></h5><p>前面已经介绍过，如果order by后面有一个联合索引的多个字段，它们具有相同排序规则，那么会走索引。</p><p>但如果它们有不同的排序规则呢？</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> user </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> code </span><span style="color:#F78C6C;">asc</span><span style="color:#A6ACCD;">,age </span><span style="color:#F78C6C;">desc</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">limit</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211721086.png" alt="image-20220921172128976" style="zoom:80%;"><p>从图中看出，尽管order by后面的code和age字段遵循了最左匹配原则，但由于一个字段是用的升序，另一个字段用的降序，最终会导致索引失效。</p><h3 id="其他" tabindex="-1">其他 <a class="header-anchor" href="#其他" aria-label="Permalink to &quot;其他&quot;">​</a></h3><blockquote><p>当然，还有其他一些是否走索引的规则，这与索引的类型是B-tree索引还是位图索引也有关系，就不再详细展开。</p></blockquote><blockquote><p>这里要说的其他，可以总结为第十五种索引失效的情况：<strong>MySQL优化器的其他优化策略，比如优化器认为在某些情况下，全表扫描比走索引快，则它就会放弃索引。</strong></p></blockquote><p>针对这种情况，一般不用过多理会，当发现问题时再定点排查即可。</p><h2 id="sql提示索引切换" tabindex="-1">SQL提示索引切换 <a class="header-anchor" href="#sql提示索引切换" aria-label="Permalink to &quot;SQL提示索引切换&quot;">​</a></h2><p>SQL提示，是优化数据库的一个重要手段，简单来说，就是在SQL语句中加入一些人为的提示来达到优化操作</p><p>那么，我们能不能在查询的时候，自己来指定使用哪个索引呢？ 答案是肯定的，此时就可以借助于</p><p>MySQL的SQL提示来完成。 接下来，介绍一下SQL提示。</p><h3 id="前期准备" tabindex="-1">前期准备 <a class="header-anchor" href="#前期准备" aria-label="Permalink to &quot;前期准备&quot;">​</a></h3><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_name</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> tb_user(</span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_name_phone</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> tb_user(</span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;">,phone);</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">吕布</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>可以看到，有两个索引推荐使用</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211027312.png" alt="image-20220921102735229" style="zoom:80%;"><h3 id="使用索引切换" tabindex="-1">使用索引切换 <a class="header-anchor" href="#使用索引切换" aria-label="Permalink to &quot;使用索引切换&quot;">​</a></h3><h4 id="use-index-推荐" tabindex="-1">use index(推荐) <a class="header-anchor" href="#use-index-推荐" aria-label="Permalink to &quot;use index(推荐)&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- use index(推荐使用自己选择的索引，当然如果自己选择的索引不好用，MySQL会自己切换好用的索引)</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user </span><span style="color:#F78C6C;">use</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;">(idx_name) </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">吕布</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211030939.png" alt="image-20220921103007839" style="zoom:80%;"><h4 id="ignore-index-忽略" tabindex="-1">ignore index(忽略) <a class="header-anchor" href="#ignore-index-忽略" aria-label="Permalink to &quot;ignore index(忽略)&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- ignore index(忽略索引，就是不去使用该索引，如果该字段多个索引，会使用其他索引)</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user </span><span style="color:#F78C6C;">ignore</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;">(idx_name) </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">吕布</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211029109.png" alt="image-20220921102927029" style="zoom:80%;"><h4 id="force-index-强制" tabindex="-1">force index(强制) <a class="header-anchor" href="#force-index-强制" aria-label="Permalink to &quot;force index(强制)&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- force index(强制使用该索引)</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user </span><span style="color:#F78C6C;">force</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;">(idx_name) </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">吕布</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211029950.png" alt="image-20220921102945872" style="zoom:80%;"><h2 id="覆盖索引-回表查询" tabindex="-1">覆盖索引 &amp; 回表查询 <a class="header-anchor" href="#覆盖索引-回表查询" aria-label="Permalink to &quot;覆盖索引 &amp; 回表查询&quot;">​</a></h2><h3 id="覆盖索引" tabindex="-1">覆盖索引 <a class="header-anchor" href="#覆盖索引" aria-label="Permalink to &quot;覆盖索引&quot;">​</a></h3><blockquote><p>覆盖索引是指在查询时，索引包含了查询需要的所有数据，而不需要再回到数据表中查找数据的一种索引使用方法。在执行查询时，MySQL可以直接使用索引中的数据返回结果，而不需要再次查询数据表，从而提高查询效率</p></blockquote><blockquote><p>举个例子，如果一个查询需要使用到一个表的 <code>id</code> 和 <code>name</code> 两个列，而这两个列已经被创建了联合索引。当查询时，如果只需要返回 <code>id</code> 和 <code>name</code> 两个列，MySQL可以直接使用索引进行查询并返回结果，而不需要再回到表中去查找数据。这种情况下就可以使用覆盖索引。使用覆盖索引的好处是减少了回表操作，降低IO开销和查询时间</p></blockquote><blockquote><p>尽量使用覆盖索引，减少select *。 那么什么是覆盖索引呢？ 覆盖索引是指 查询使用了索引，并且需要返回的列，</p><p>在该索引中已经全部能够找到 。 重点：不能用select *</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206181430327.png" alt="image-20220618143024237" style="zoom:67%;"><p>思考题：一张表, 有四个字段(id, username, password, status), 由于数据量大, 对SQL语句进行优化, 如何才是最优</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,username,</span><span style="color:#F78C6C;">password</span><span style="color:#A6ACCD;"> </span></span>
<span class="line"><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user </span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> username </span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">itcast</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>答案: 针对于 username, password建立联合索引, sql为:</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_user_name_pass</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> tb_user(username,</span><span style="color:#F78C6C;">password</span><span style="color:#A6ACCD;">);</span></span></code></pre></div><p>这样可以避免上述的SQL语句，在查询的过程中，出现回表查询。</p><h3 id="回表查询" tabindex="-1">回表查询 <a class="header-anchor" href="#回表查询" aria-label="Permalink to &quot;回表查询&quot;">​</a></h3><blockquote><p>回表查询是指当需要查询的字段不在覆盖索引中时，MySQL需要通过回到主键索引树上，再通过主键索引找到对应的数据行，从而获取其他字段的值的过程。这个过程需要额外的IO操作和CPU计算，会导致查询效率的降低，特别是对于大表而言，回表查询的开销很大。因此，尽可能使用覆盖索引可以避免回表查询，提高查询效率。</p></blockquote><p>A. 表结构及索引示意图:</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206181434329.png" alt="image-20220618143420216" style="zoom:67%;"><p>id是主键，是一个聚集索引。 name字段建立了普通索引，是一个二级索引（辅助索引）。</p><p>B. 执行SQL : select * from tb_user where id = 2;</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206181434708.png" alt="image-20220618143450595" style="zoom:67%;"><p>根据id查询，直接走聚集索引查询，一次索引扫描，直接返回数据，性能高。</p><p>C. 执行SQL：selet id,name from tb_user where name = &#39;Arm&#39;;</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206181435502.png" alt="image-20220618143519402" style="zoom:67%;"><p>虽然是根据name字段查询，查询二级索引，但是由于查询返回在字段为 id，name，在name的二级索引中，这两个值都</p><p>是可以直接获取到的，因为覆盖索引，所以不需要回表查询，性能高。</p><p>D. 执行SQL：selet id,name,gender from tb_user where name = &#39;Arm&#39;;</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206181436531.png" alt="image-20220618143606424" style="zoom:67%;"><p>由于在name的二级索引中，不包含gender，所以，需要两次索引扫描，也就是需要回表查询，性能相对较差一点。</p><h2 id="前缀索引" tabindex="-1">前缀索引 <a class="header-anchor" href="#前缀索引" aria-label="Permalink to &quot;前缀索引&quot;">​</a></h2><blockquote><p><strong>当字段类型为字符串（varchar，text等）时，有时候需要索引很长的字符串，这会让索引变得很大，查询时，浪费大量的磁盘IO， 影响查询效率</strong>。此时可以只将字符串的一部分前缀，建立索引，这样可以大大节约索引空间，从而提高索引效率。<strong>短索引不仅可以提高查询速度而且可以节省磁盘空间、减少 I/O 操作。</strong></p></blockquote><p>例如，如果有一个 CHAR(255) 的列，如果在前 10 个或 30 个字符内，多数值是惟一的，则不需要对整个列进行索引。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_xxx</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> table_name(column(n));</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_lucifer_name</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> lucifer (</span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">4</span><span style="color:#A6ACCD;">));</span></span></code></pre></div><ul><li>column表示字段名</li><li>n表示截取字段长度</li></ul><h3 id="前缀长度选择" tabindex="-1">前缀长度选择 <a class="header-anchor" href="#前缀长度选择" aria-label="Permalink to &quot;前缀长度选择&quot;">​</a></h3><p>可以根据索引的选择性来决定，而选择性是指不重复的索引值（基数）和数据表的记录总数的比值，<strong>索引选择性越高则查询效率越高</strong>。</p><p>例如唯一索引的选择性是1，这是最好的索引选择性，性能也是最好的。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 1.0000</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">distinct</span><span style="color:#A6ACCD;"> username)</span><span style="color:#89DDFF;">/</span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 0.9590</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">distinct</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">substring</span><span style="color:#A6ACCD;">(username,</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">5</span><span style="color:#A6ACCD;">))</span><span style="color:#89DDFF;">/</span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 0.9984</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">distinct</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">substring</span><span style="color:#A6ACCD;">(username,</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">6</span><span style="color:#A6ACCD;">))</span><span style="color:#89DDFF;">/</span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 0.9999</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">distinct</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">substring</span><span style="color:#A6ACCD;">(username,</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">7</span><span style="color:#A6ACCD;">))</span><span style="color:#89DDFF;">/</span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user;</span></span></code></pre></div><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 由上面建立索引</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_username</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> tb_user(username(</span><span style="color:#F78C6C;">7</span><span style="color:#A6ACCD;">));</span></span></code></pre></div><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user;</span></span></code></pre></div><h3 id="前缀索引查询流程" tabindex="-1">前缀索引查询流程 <a class="header-anchor" href="#前缀索引查询流程" aria-label="Permalink to &quot;前缀索引查询流程&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220410113337429.png" alt="image-20220410113337429" style="zoom:67%;"><h2 id="单列索引-联合索引" tabindex="-1">单列索引 &amp; 联合索引 <a class="header-anchor" href="#单列索引-联合索引" aria-label="Permalink to &quot;单列索引 &amp; 联合索引&quot;">​</a></h2><blockquote><p>单列索引：<strong>即一个索引只包含单个列</strong>。</p><p>联合索引：<strong>即一个索引包含了多个列。联合索引要满足最左前缀，详见最左前缀法则那一节</strong></p><p>在业务场景中，<strong>如果存在多个查询条件，考虑针对于查询字段建立索引时，建议建立联合索引，而非单列索引</strong>。</p></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,username, </span><span style="color:#F78C6C;">password</span><span style="color:#A6ACCD;"> </span></span>
<span class="line"><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user </span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> username</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">zmcTTgUSDV1</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">and</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">password</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">zmcTTgUSDV</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220410113844829.png" alt="image-20220410113844829" style="zoom:80%;"><blockquote><p><strong>多条件联合查询时，MYSQL优化器会评估哪个字段索引效率更高，会选择该索引完成本次查询</strong></p></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_user_pro_age_sta</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> tb_user(profession, age,</span><span style="color:#F78C6C;">status</span><span style="color:#A6ACCD;">);</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220410113939687.png" alt="image-20220410113939687" style="zoom:67%;"><h2 id="索引长度计算" tabindex="-1">索引长度计算 <a class="header-anchor" href="#索引长度计算" aria-label="Permalink to &quot;索引长度计算&quot;">​</a></h2><h3 id="索引长度公式" tabindex="-1">索引长度公式 <a class="header-anchor" href="#索引长度公式" aria-label="Permalink to &quot;索引长度公式&quot;">​</a></h3><blockquote><p>1.所有的索引字段，如果没有设置not null，则需要加一个字节。</p><p>2.定长字段，int占四个字节、date占三个字节、char(n)占n个字符。</p><p>3.对于变成字段varchar(n)，则有n个字符+两个字节。</p><p>4.不同的字符集，一个字符占用的字节数不同。latin1编码的，一个字符占用一个字节，gbk编码的，一个字符占用两个字节，utf8编码的，一个字符占用三个字节。</p><p>5.索引长度 char()、varchar()索引长度的计算公式：</p></blockquote><blockquote><p>Character Set：utf8mb4=4,utf8=3,gbk=2,latin1=1) * 列长度 + 1(允许null) + 2(变长列)</p></blockquote><h3 id="实战演练" tabindex="-1">实战演练 <a class="header-anchor" href="#实战演练" aria-label="Permalink to &quot;实战演练&quot;">​</a></h3><h4 id="数据准备" tabindex="-1">数据准备 <a class="header-anchor" href="#数据准备" aria-label="Permalink to &quot;数据准备&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">table</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">account</span><span style="color:#A6ACCD;"> (</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">not null</span><span style="color:#A6ACCD;"> auto_increment comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">主键id</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;">) </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">姓名</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">money</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">余额</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#C792EA;">primary key</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">) engine</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">innodb comment</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">账户表</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">show </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> account;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_name_money</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> account(</span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;">,</span><span style="color:#C792EA;">money</span><span style="color:#A6ACCD;">);</span></span></code></pre></div><h4 id="索引分析" tabindex="-1">索引分析 <a class="header-anchor" href="#索引分析" aria-label="Permalink to &quot;索引分析&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;"># </span><span style="color:#F78C6C;">10</span><span style="color:#89DDFF;">*</span><span style="color:#F78C6C;">4</span><span style="color:#89DDFF;">+</span><span style="color:#F78C6C;">2</span><span style="color:#89DDFF;">+</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">43</span><span style="color:#A6ACCD;">,2个汉字</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">4个字节</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> account </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">张三</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;"># </span><span style="color:#F78C6C;">43</span><span style="color:#89DDFF;">+</span><span style="color:#F78C6C;">4</span><span style="color:#89DDFF;">+</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">48</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> account </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">张三</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">and</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">money</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2000</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;"># </span><span style="color:#F78C6C;">4</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> account </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain select * from t_user where id_no = &#39;1002&#39;;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011008543.png" alt="image-20230301100807439" style="zoom:80%;"><p>通过explain执行结果可以看出，上述SQL语句走了<code>union_idx</code>这条索引。这里再普及一下key_len的计算：</p><ul><li>id_no 类型为varchar(18)，字符集为utf8mb4_bin，也就是使用4个字节来表示一个完整的UTF-8。此时，key_len = 18* 4 = 72；</li><li>由于该字段类型varchar为变长数据类型，需要再额外添加2个字节。此时，key_len = 72 + 2 = 74；</li><li>由于该字段运行为NULL（default NULL），需要再添加1个字节。此时，key_len = 74 + 1 = 75；</li></ul><p>上面演示了key_len一种情况的计算过程，后续不再进行逐一推演，知道基本组成和原理即可</p><h2 id="索引设计原则" tabindex="-1">索引设计原则 <a class="header-anchor" href="#索引设计原则" aria-label="Permalink to &quot;索引设计原则&quot;">​</a></h2><blockquote><ul><li><strong>针对于数据量较大(100万)，且查询比较频繁的表建立索引</strong>。</li><li>针对于<strong>常作为查询条件（where）、排序（order by）、分组（group by）操作的字段</strong>建立索引。</li><li>尽量选择<strong>区分度高的列作为索引，尽量建立唯一索引，区分度越高，使用索引的效率越高</strong>。</li><li>如果是<strong>字符串类型的字段，字段的长度较长，可以针对于字段的特点，建立前缀索引</strong>。</li><li><strong>尽量使用联合索引，减少单列索引，查询时，联合索引很多时候可以覆盖索引，节省存储空间，避免回表</strong></li><li>要<strong>控制索引的数量，索引越多，维护索引结构的代价也就越大，会影响增删改的效率</strong></li><li><strong>如果索引列不能存储NULL值，请在创建表时使用NOT NULL约束它</strong>。<strong>当优化器知道每列是否包含NULL值时，它可以更好地确定哪个索引最有效地用于查询</strong>。</li></ul></blockquote><h1 id="性能分析⭐" tabindex="-1">性能分析⭐ <a class="header-anchor" href="#性能分析⭐" aria-label="Permalink to &quot;性能分析⭐&quot;">​</a></h1><h2 id="sql执行频率" tabindex="-1">SQL执行频率 <a class="header-anchor" href="#sql执行频率" aria-label="Permalink to &quot;SQL执行频率&quot;">​</a></h2><p>MySQL 客户端连接成功后，通过 show [session|global] status 命令可以提供服务器状态信息。通过如下指令，可以查看当前数据库 的INSERT、UPDATE、DELETE、SELECT的访问频次：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- session 是查看当前会话 ; global 是查询全局数据 </span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 注意：是7个下划线</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 注意看select、update、delete、的执行次数</span></span>
<span class="line"><span style="color:#A6ACCD;">show </span><span style="color:#F78C6C;">global</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">status</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">Com_______</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220123112001280.png" alt="image-20220123112001280" style="zoom:80%;"><p>我们可以在当前数据库再执行几次查询操作，然后再次查看执行频次，看看 Com_select 参数会不会变化</p><blockquote><p>通过上述指令，我们可以查看到当前数据库到底是以查询为主，还是以增删改为主，从而为数据库优化提供参考依据。 如果是以增删改为主，我们可以考虑不对其进行索引的优化。 如果是以查询为主，那么就要考虑对数据库的索引进行优化了。</p></blockquote><blockquote><p>那么通过查询SQL的执行频次，我们就能够知道当前数据库到底是增删改为主，还是查询为主。 那假如说是以查询为主，我们又该如何定位针对于那些查询语句进行优化呢？ 次数我们可以借助于慢查询日志。</p></blockquote><h2 id="慢日志查询⭐" tabindex="-1">慢日志查询⭐ <a class="header-anchor" href="#慢日志查询⭐" aria-label="Permalink to &quot;慢日志查询⭐&quot;">​</a></h2><blockquote><p>慢查询日志记录了所有执行时间超过指定参数（long_query_time，单位：秒，默认10秒）的所有SQL语句的日志。MySQL的慢查询日志默认没有开启，需要在MySQL的配置文件（my.ini）中配置如下信息：这几个参数一定要配好，再根据每条慢查询对症下药，像我司每天都会把这些慢查询提取出来通过邮件给形式发送给各个业务团队，以帮忙定位解决。</p></blockquote><h3 id="开启慢日志" tabindex="-1">开启慢日志 <a class="header-anchor" href="#开启慢日志" aria-label="Permalink to &quot;开启慢日志&quot;">​</a></h3><div class="language-ini"><button title="Copy Code" class="copy"></button><span class="lang">ini</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">vim /etc/my.cnf</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 开启MySQL慢日志查询开关，0表示关闭，1表示开启</span></span>
<span class="line"><span style="color:#F07178;">slow-query-log</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">1</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 设置慢日志时间(默认10s)，SQL执行时间超过10s，就会视为慢查询，记录慢查询日志</span></span>
<span class="line"><span style="color:#F07178;">long_query_time</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">2</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 设置慢查询日志存储位置，可选，有默认值</span></span>
<span class="line"><span style="color:#F07178;">slow_query_log_file</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> /var/log/mysql/slow.log</span></span></code></pre></div><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 查看是否开启慢查询ON表示开启</span></span>
<span class="line"><span style="color:#A6ACCD;">show variables </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%slow_query_log%</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202302281925068.png" alt="image-20230228192505991" style="zoom:67%;"><p>配置完毕之后，通过以下指令重新启动MySQL服务器进行测试，查看慢日志文件中记录的信息</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">systemctl restart mysqld</span></span></code></pre></div><p>然后，再次查看开关情况，慢查询日志就已经打开了。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220410102829088.png" alt="image-20220410102829088" style="zoom:67%;"><h3 id="测试慢查询" tabindex="-1">测试慢查询 <a class="header-anchor" href="#测试慢查询" aria-label="Permalink to &quot;测试慢查询&quot;">​</a></h3><p>A. 执行如下SQL语句 ：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 查询时睡眠，执行了48s</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;">,sleep(</span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user;</span></span></code></pre></div><p>B. 检查慢查询日志 ：</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">tail </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">f </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">var</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">lib</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mysql</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">slow</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">log</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209210836865.png" alt="image-20220921083600757" style="zoom:80%;"><p>这样，通过慢查询日志，就可以定位出执行效率比较低的SQL，从而有针对性的进行优化。</p><h2 id="sql执行耗时详情" tabindex="-1">SQL执行耗时详情 <a class="header-anchor" href="#sql执行耗时详情" aria-label="Permalink to &quot;SQL执行耗时详情&quot;">​</a></h2><p>show profiles 能够在做SQL优化时帮助我们了解<strong>时间都耗费到哪里去</strong>了。通过have_profiling参数，能够看到当前MySQL是否支持profile操作：</p><p>使用DataGrip查询会出现问题，显示一堆奇怪的东西，因此使用命令行进行查询</p><p>注意：<code>只能看当前窗口执行的SQL，不能看到其他地方的SQL</code></p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 性能分析</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 查看是否支持</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> @@have_profiling;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 一般都没开启，要在这里开启</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 进行开启:0表示没开启，1表示开启</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> @@profiling;</span></span>
<span class="line"><span style="color:#F78C6C;">set</span><span style="color:#A6ACCD;"> profiling </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 查看执行SQL的耗时情况</span></span>
<span class="line"><span style="color:#A6ACCD;">show profiles ;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 查看单条语句详细耗时情况，query后面跟的是query_id</span></span>
<span class="line"><span style="color:#A6ACCD;">show </span><span style="color:#F78C6C;">profile</span><span style="color:#A6ACCD;"> for query </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 查看cpu消耗情况，后面跟的是query_id</span></span>
<span class="line"><span style="color:#A6ACCD;">show </span><span style="color:#F78C6C;">profile</span><span style="color:#A6ACCD;"> cpu for query </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220123113329392.png" alt="image-20220123113329392" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206181413450.png" alt="image-20220618141323343" style="zoom:67%;"><h2 id="processlist压力情况" tabindex="-1">processlist压力情况 <a class="header-anchor" href="#processlist压力情况" aria-label="Permalink to &quot;processlist压力情况&quot;">​</a></h2><blockquote><p>MySQL的Processlist是用于显示当前正在执行的查询和线程的列表的命令，可以用来监视服务器的状态和性能。</p></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;"># 可以查看当前 MySQL 是否有压力，正在运行的SQL，有没有慢SQL正在执行。</span></span>
<span class="line"><span style="color:#A6ACCD;">show processlist;</span></span>
<span class="line"><span style="color:#A6ACCD;"># FULL关键字可选，用于显示完整的进程信息，包括当前查询正在使用的资源（如CPU、</span><span style="color:#F78C6C;">IO</span><span style="color:#A6ACCD;">、锁等）情况。</span></span>
<span class="line"><span style="color:#A6ACCD;"># 如果不指定FULL，则只会显示查询语句和状态。</span></span>
<span class="line"><span style="color:#A6ACCD;">show full processlist</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209210839629.png" alt="image-20220921083956549" style="zoom:80%;"><p>执行上述命令后，MySQL会返回一个结果集，包含以下几个字段：</p><ul><li>ID：线程ID；</li><li>USER：连接到MySQL服务器的用户名；</li><li>HOST：客户端的主机名；</li><li>DB：当前查询所在的数据库；</li><li>COMMAND：查询类型，如SELECT、UPDATE等；</li><li>TIME：当前查询已经执行的时间（秒）；</li><li>STATE：当前查询的状态；</li><li>INFO：当前查询的详细信息。</li></ul><blockquote><p>需要注意的是，使用SHOW PROCESSLIST命令会对MySQL的性能产生一定的影响，因为它需要查询系统资源来获取信息。因此，在高并发或高负载的环境下，需要谨慎使用。</p></blockquote><h2 id="explain执行计划⭐" tabindex="-1">explain执行计划⭐ <a class="header-anchor" href="#explain执行计划⭐" aria-label="Permalink to &quot;explain执行计划⭐&quot;">​</a></h2><h3 id="基本语法-1" tabindex="-1">基本语法 <a class="header-anchor" href="#基本语法-1" aria-label="Permalink to &quot;基本语法&quot;">​</a></h3><blockquote><ul><li><p>EXPLAIN可以使用于 SELECT， DELETE， INSERT， REPLACE，和 UPDATE语句。</p></li><li><p>当EXPLAIN与可解释的语句一起使用时，MySQL将显示来自优化器的有关语句执行计划的信息。也就是说，MySQL解释了它将如何处理该语句，包括有关如何连接表以及以何种顺序连接表的信息。</p></li><li><p>当EXPLAIN与非可解释的语句一起使用时，它将显示在命名连接中执行的语句的执行计划。</p></li><li><p>对于SELECT语句， EXPLAIN可以显示的其他执行计划的警告信息</p></li></ul></blockquote><blockquote><p>EXPLAIN 或者 DESC命令获取 MySQL 如何执行 SELECT 语句的信息，包括在 SELECT 语句执行过程中表如何连接和连接的顺序。语法：</p></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 直接在select语句之前加上关键字：explain或desc</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">desc</span><span style="color:#A6ACCD;"> EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> 字段列表 </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> 表名 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> 条件 ;</span></span></code></pre></div><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 只需要在SQL前面加上explain或desc即可</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> author;</span></span>
<span class="line"><span style="color:#F78C6C;">desc</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> author;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220410104203968.png" alt="image-20220410104203968" style="zoom:67%;"><p>从上图中看到执行结果中会显示12列信息，每列具体信息如下：说白了，我们要搞懂这些列的具体含义才能正常判断索引的使用情况。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202302281946139.png" alt="image-20230228194606001" style="zoom:80%;"><h3 id="id列" tabindex="-1">id列 <a class="header-anchor" href="#id列" aria-label="Permalink to &quot;id列&quot;">​</a></h3><blockquote><p>实际上每次select查询都会对应一个id，它代表着SQL执行的顺序，如果id值越大，说明对应的SQL语句执行的优先级越高。在一些复杂的查询SQL语句中常常包含一些子查询，那么id序号就会递增，如果出现嵌套查询，我们可以发现最里层的查询对应的id最大，因此也优先被执行。id值相同，执行顺序是从上到下</p></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 查询学生选课情况(多对多查询)</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> student s,course c, student_course sc</span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> s.id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> sc.studentid </span><span style="color:#F78C6C;">and</span><span style="color:#A6ACCD;"> c.id</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">sc.studentid;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209210848855.png" alt="image-20220921084836780" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209210849152.png" alt="image-20220921084927074" style="zoom:80%;"><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 查询选修了MySQL学生，子查询实现</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> course c </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> c.name</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">MySQL</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> studentid </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> student_course sc </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> sc.courseid </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">3</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> student s </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> s.id </span><span style="color:#F78C6C;">in</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 子查询完整实现</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> student s</span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> s.id </span><span style="color:#F78C6C;">in</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> studentid </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> student_course sc </span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> sc.courseid</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> course c </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> c.name</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">MySQL</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">));</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209210856842.png" alt="image-20220921085657769" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209210857914.png" alt="image-20220921085743841" style="zoom:80%;"><h3 id="select-type⭐" tabindex="-1">select_type⭐ <a class="header-anchor" href="#select-type⭐" aria-label="Permalink to &quot;select_type⭐&quot;">​</a></h3><blockquote><p>select_type表示的执行计划的对应的查询是什么类型，常见查询类型包括<strong>普通查询、联合查询以及子查询</strong></p></blockquote><p>该列表示select的类型。具体包含了如下11种类型：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022/202204281234321.png" alt="image-20220428123452232" style="zoom:60%;"><p>但是常用的其实就是下面几个：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303010935225.png" alt="image-20230301093510077" style="zoom:80%;"><h3 id="partitions" tabindex="-1">partitions <a class="header-anchor" href="#partitions" aria-label="Permalink to &quot;partitions&quot;">​</a></h3><blockquote><p>partitions代表的是分区的概念，表示在进行查询时,如果对应的表存在分区表，那么这里就会显示具体的分区信息</p></blockquote><h3 id="type列⭐⭐" tabindex="-1">type列⭐⭐ <a class="header-anchor" href="#type列⭐⭐" aria-label="Permalink to &quot;type列⭐⭐&quot;">​</a></h3><blockquote><p>type是非常核心的属性，需要重点掌握。它表示的是当前通过什么样的方式对数据库表进行分访问。该列的值表示连接类型，是查看索引执行情况的一个重要指标。<strong>执行性能从最坏到最好的的顺序是从上到下</strong></p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202302281943594.png" alt="image-20230228194303464" style="zoom:80%;"><h3 id="possible-keys⭐" tabindex="-1">possible_keys⭐ <a class="header-anchor" href="#possible-keys⭐" aria-label="Permalink to &quot;possible_keys⭐&quot;">​</a></h3><blockquote><p><strong>表示哪些索引可以被MySQL的优化器进行选择，也就是索引候选者有哪些</strong>。</p></blockquote><h3 id="key⭐" tabindex="-1">key⭐ <a class="header-anchor" href="#key⭐" aria-label="Permalink to &quot;key⭐&quot;">​</a></h3><blockquote><p><strong>在possible_keys中实际选择的索引，如果为NULL，则没有使用索引</strong></p></blockquote><h3 id="key-len⭐" tabindex="-1">key_len⭐ <a class="header-anchor" href="#key-len⭐" aria-label="Permalink to &quot;key_len⭐&quot;">​</a></h3><blockquote><p><strong>表示索引的长度，和实际的字段属性以及是否为null都有关系。在不损失精度的情况下长度越短越好</strong></p></blockquote><h3 id="ref" tabindex="-1">ref <a class="header-anchor" href="#ref" aria-label="Permalink to &quot;ref&quot;">​</a></h3><blockquote><p><strong>当使用字段进行常量等值查询时ref此处为const，当查询条件中使用了表达式或者函数则ref显示为func，则其他的显示为null。</strong></p></blockquote><h3 id="rows⭐" tabindex="-1">rows⭐ <a class="header-anchor" href="#rows⭐" aria-label="Permalink to &quot;rows⭐&quot;">​</a></h3><blockquote><p><strong>rows列显示MySQL认为它执行查询时必须检查的行数。行数越少，效率越高！是一个预估值，不太准确</strong></p></blockquote><h3 id="filtered" tabindex="-1">filtered <a class="header-anchor" href="#filtered" aria-label="Permalink to &quot;filtered&quot;">​</a></h3><blockquote><p><strong>filtered 这个是一个百分比的值，表里符合条件的记录数的百分比。简单点说，这个字段表示存储引擎返回的数据在经过过滤后，剩下的记录满足条件的记录数量的比例。值越大越好</strong></p></blockquote><h3 id="extra列⭐" tabindex="-1">Extra列⭐ <a class="header-anchor" href="#extra列⭐" aria-label="Permalink to &quot;Extra列⭐&quot;">​</a></h3><blockquote><p>Extra 是 EXPLAIN 输出中另外一个很重要的列，该列显示 MySQL 在查询过程中的一些详细信息，MySQL 查询优化器执行查询的过程中对查询计划的重要补充信息。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202302281948864.png" alt="image-20230228194841749" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202302281949401.png" alt="image-20230228194905292" style="zoom:80%;"><h1 id="视图-存储过程-触发器" tabindex="-1">视图/存储过程/触发器 <a class="header-anchor" href="#视图-存储过程-触发器" aria-label="Permalink to &quot;视图/存储过程/触发器&quot;">​</a></h1><p>大公司不允许使用MySQL的存储过程和触发器的原因可能包括以下几点：</p><blockquote><p>一致性问题：存储过程和触发器可能会影响数据库的一致性。如果使用不当，可能会导致数据不一致或数据丢失等问题。</p></blockquote><blockquote><p>可维护性问题：存储过程和触发器通常比较复杂，难以理解和维护。当数据库规模变得越来越大时，这些复杂的存储过程和触发器可能会变得难以管理和维护。</p></blockquote><blockquote><p>性能问题：存储过程和触发器可能会对数据库的性能产生负面影响。它们需要额外的资源来运行，并且可能会降低查询和更新的速度。</p></blockquote><blockquote><p>安全问题：存储过程和触发器可能会成为安全漏洞。攻击者可能会通过存储过程和触发器来执行恶意代码或访问敏感信息。</p></blockquote><blockquote><p>综上所述，存储过程和触发器并不是适合所有情况的解决方案。在某些情况下，它们可以提供很好的性能和灵活性，但在其他情况下，它们可能会成为问题所在。因此，在使用存储过程和触发器之前，应该仔细考虑它们的优缺点，并确保使用正确和安全的方式来实现它们。</p></blockquote><h2 id="视图" tabindex="-1">视图 <a class="header-anchor" href="#视图" aria-label="Permalink to &quot;视图&quot;">​</a></h2><p>含义：虚拟表，创建一张虚拟表，和普通表一样使用，MySQL5.1版本出现的新特性，是通过表动态生成的数据</p><blockquote><p>视图中的数据并不在数据库中实际存在，行和列数据来自定义视图的查询中使用的表，并且是在使用视图时动态生成的。通俗的讲，视图只保存了查询的SQL逻辑，不保存查询结果。所以我们在创建视图的时候，主要的工作就落在创建这条SQL查询语句上。</p></blockquote><blockquote><p>视图不仅可以简化用户对数据的理解，也可以简化他们的操作。那些被经常使用的查询可以被定义为视图，从而使得用户不必为以后的操作每次指定全部的条件。数据库可以授权，但不能授权到数据库特定行和特定的列上。通过视图用户只能查询和修改他们所能见到的数据.视图可帮助用户屏蔽真实表结构变化带来的影响。</p><p>总结：简单，安全，数据独立</p></blockquote><h3 id="增删改查视图" tabindex="-1">增删改查视图 <a class="header-anchor" href="#增删改查视图" aria-label="Permalink to &quot;增删改查视图&quot;">​</a></h3><h4 id="创建视图" tabindex="-1">创建视图 <a class="header-anchor" href="#创建视图" aria-label="Permalink to &quot;创建视图&quot;">​</a></h4><p>在原有基础表上进行一次SQL操作，生成一个视图</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 创建视图</span></span>
<span class="line"><span style="color:#F78C6C;">create or replace</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">view</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">视图名</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">as</span><span style="color:#A6ACCD;"> SQL查询语句</span></span>
<span class="line"><span style="color:#F78C6C;">create or replace</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">view</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">account_view</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">as</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,</span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> account;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209212257006.png" alt="image-20220921225749896" style="zoom:80%;"><h4 id="查看视图" tabindex="-1">查看视图 <a class="header-anchor" href="#查看视图" aria-label="Permalink to &quot;查看视图&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 查看创建视图语句</span></span>
<span class="line"><span style="color:#A6ACCD;">show </span><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> view account_view;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 查询内容</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> account_view;</span></span></code></pre></div><h4 id="修改视图" tabindex="-1">修改视图 <a class="header-anchor" href="#修改视图" aria-label="Permalink to &quot;修改视图&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">#方式一：修改视图(同新建视图，重点在于or </span><span style="color:#F78C6C;">replace</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#F78C6C;">create or replace</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">view</span><span style="color:#A6ACCD;">  </span><span style="color:#82AAFF;">视图名</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">as</span><span style="color:#A6ACCD;"> 查询语句;</span></span>
<span class="line"><span style="color:#A6ACCD;">#方式二</span></span>
<span class="line"><span style="color:#F78C6C;">alter</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">view</span><span style="color:#A6ACCD;"> 视图名 </span><span style="color:#F78C6C;">as</span><span style="color:#A6ACCD;"> 查询语句;</span></span></code></pre></div><h4 id="删除视图" tabindex="-1">删除视图 <a class="header-anchor" href="#删除视图" aria-label="Permalink to &quot;删除视图&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">语法：</span><span style="color:#F78C6C;">drop</span><span style="color:#A6ACCD;"> view 视图名,视图名,...;</span></span></code></pre></div><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">drop</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">view</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">if</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">exists</span><span style="color:#A6ACCD;"> v1;</span></span></code></pre></div><h4 id="查看视图结构" tabindex="-1">查看视图结构 <a class="header-anchor" href="#查看视图结构" aria-label="Permalink to &quot;查看视图结构&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">desc</span><span style="color:#A6ACCD;"> account_view;  # 查看视图表结构</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">show </span><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> view account_view; # 查看视图编码等情况</span></span></code></pre></div><h4 id="增删改视图内容⭐⭐" tabindex="-1">增删改视图内容⭐⭐ <a class="header-anchor" href="#增删改视图内容⭐⭐" aria-label="Permalink to &quot;增删改视图内容⭐⭐&quot;">​</a></h4><blockquote><p>注意：<strong>不用在视图中增删改数据，在原表中增删改数据会自动影响到视图的，视图增删改操作相同</strong></p></blockquote><blockquote><p>注意：具备以下特点的视图<strong>不允许更新</strong> 包含以下关键字的sql语句：分组函数sum,count,max、distinct、group by、having、union或者union all</p></blockquote><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 视图的更新</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 视图中的行要和基础表中的行是一对一的关系(即对应基础表中的数据)</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 这个视图就不能进行更新等操作</span></span>
<span class="line"><span style="color:#A6ACCD;">create view stu_c as</span></span>
<span class="line"><span style="color:#A6ACCD;">select count(*) &#39;总数&#39;,min(userCP) &#39;最小&#39; ,max(userCP) &#39;最大&#39; from boys;</span></span></code></pre></div><h3 id="检查选项⭐" tabindex="-1">检查选项⭐ <a class="header-anchor" href="#检查选项⭐" aria-label="Permalink to &quot;检查选项⭐&quot;">​</a></h3><blockquote><p>该目的是确保插入视图的内容是符合视图的定义的，MySQL视图的<code>WITH CHECK OPTION</code>选项是用于保护视图的数据完整性的一种约束。它指示MySQL确保视图中的所有行都符合定义该视图的WHERE子句中的条件。</p></blockquote><blockquote><p>当使用WITH CHECK OPTION子句创建视图时，MySQL会通过视图检查正在更改的每个行，例如 插入，更新，删除，<strong>以使其符合视图的定义</strong>。MySQL允许基于另一个视图创建视图，它还会检查依赖视图中的规则以保持一致性。为了确定检查的范围，MySQL提供了两个选项：CASCADED 和 LOCAL ，默认值为 CASCADED 。</p></blockquote><blockquote><p>cascaded：如果您更改了视图中基表的结构，则MySQL<strong>会重新编译与该视图相关的任何视图</strong>。这是因为更改基表可能会影响到其他视图。如果您在创建视图时指定了cascaded选项，则任何视图都会重新编译。这是默认选项。</p><p>local：如果您在创建视图时指定了local选项，则仅在更改基表的结构后，与该视图直接相关的视图才会重新编译</p></blockquote><blockquote><p>因此，cascaded选项会重新编译与视图相关的所有视图，而local选项<strong>只会重新编译与该视图直接相关的视图</strong>。如果您的数据库中包含大量视图，则cascaded选项可能会导致性能问题。因此，建议在创建视图时指定local选项，以避免不必要的重新编译。</p></blockquote><h4 id="cascaded级联-默认" tabindex="-1">CASCADED级联(默认) <a class="header-anchor" href="#cascaded级联-默认" aria-label="Permalink to &quot;CASCADED级联(默认)&quot;">​</a></h4><p>比如，v2视图是基于v1视图的，如果在v2视图创建的时候指定了检查选项为 cascaded，但是v1视图创建时未指定检查选</p><p>项。 则在执行检查时，不仅会检查v2，还会级联检查v2的关联视图v1。不满足两个条件就不会插入数据到视图中</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209212307348.png" alt="image-20220921230710218" style="zoom:80%;"><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 检查选项，默认cascaded</span></span>
<span class="line"><span style="color:#F78C6C;">create or replace</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">view</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">usr1</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">as</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,boyName,userCP </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> boys </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> userCP </span><span style="color:#89DDFF;">&lt;=</span><span style="color:#F78C6C;">400</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 检查选项</span></span>
<span class="line"><span style="color:#F78C6C;">with</span><span style="color:#A6ACCD;"> cascaded </span><span style="color:#C792EA;">check</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">option</span><span style="color:#A6ACCD;"> ;</span></span></code></pre></div><h4 id="local本地" tabindex="-1">LOCAL本地 <a class="header-anchor" href="#local本地" aria-label="Permalink to &quot;LOCAL本地&quot;">​</a></h4><p>比如，v2视图是基于v1视图的，如果在v2视图创建的时候指定了检查选项为 local ，但是v1视图创</p><p>建时未指定检查选项。 则在执行检查时，只会检查v2，不会检查v2的关联视图v1。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220410115727035.png" alt="image-20220410115727035" style="zoom:67%;"><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 同样可以根据一个视图去创建另一个视图,虽然有下划线错，但能正常执行</span></span>
<span class="line"><span style="color:#A6ACCD;">-- cascaded增删改时会检查当前视图和当前视图所依赖的所有视图</span></span>
<span class="line"><span style="color:#A6ACCD;">create or replace view usr2 as</span></span>
<span class="line"><span style="color:#A6ACCD;">select id,boyName,userCP from usr1 where userCP &gt;=100</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 检查选项</span></span>
<span class="line"><span style="color:#A6ACCD;">with local check option ;</span></span></code></pre></div><h3 id="实战演练-1" tabindex="-1">实战演练 <a class="header-anchor" href="#实战演练-1" aria-label="Permalink to &quot;实战演练&quot;">​</a></h3><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 为了保证数据库表的安全性，开发人员在操作tb_user表时，</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 只能看到的用户的基本字段，屏蔽手机号和邮箱两个字段。</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">view</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">tb_user_view</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">as</span><span style="color:#A6ACCD;"> </span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,</span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;">,profession,age,gender,</span><span style="color:#F78C6C;">status</span><span style="color:#A6ACCD;">,createtime </span></span>
<span class="line"><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user;</span></span></code></pre></div><h4 id="子查询" tabindex="-1">子查询 <a class="header-anchor" href="#子查询" aria-label="Permalink to &quot;子查询&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">CREATE OR REPLACE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">VIEW</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">myv3</span></span>
<span class="line"><span style="color:#F78C6C;">AS</span></span>
<span class="line"><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> department_id,(</span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">MAX</span><span style="color:#A6ACCD;">(salary) </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> employees) 最高工资</span></span>
<span class="line"><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> departments;</span></span></code></pre></div><h4 id="多表查询" tabindex="-1">多表查询 <a class="header-anchor" href="#多表查询" aria-label="Permalink to &quot;多表查询&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">CREATE OR REPLACE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">VIEW</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">myv4</span></span>
<span class="line"><span style="color:#F78C6C;">AS</span></span>
<span class="line"><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> last_name,department_name</span></span>
<span class="line"><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> employees e</span></span>
<span class="line"><span style="color:#F78C6C;">JOIN</span><span style="color:#A6ACCD;"> departments d</span></span>
<span class="line"><span style="color:#F78C6C;">ON</span><span style="color:#A6ACCD;"> e.department_id  </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> d.department_id;</span></span></code></pre></div><p>where子句的子查询引用了from子句中的表</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">CREATE OR REPLACE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">VIEW</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">myv6</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">AS</span></span>
<span class="line"><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> last_name,email,salary</span></span>
<span class="line"><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> employees</span></span>
<span class="line"><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> employee_id </span><span style="color:#F78C6C;">IN</span><span style="color:#A6ACCD;">(</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;">  manager_id</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> employees</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> manager_id </span><span style="color:#F78C6C;">IS NOT NULL</span></span>
<span class="line"><span style="color:#A6ACCD;">);</span></span></code></pre></div><p>视图多表查询保存结果</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">create table student(</span></span>
<span class="line"><span style="color:#A6ACCD;">    id   int auto_increment comment &#39;主键ID&#39; primary key,</span></span>
<span class="line"><span style="color:#A6ACCD;">    name varchar(10) null comment &#39;姓名&#39;,</span></span>
<span class="line"><span style="color:#A6ACCD;">    no   varchar(10) null comment &#39;学号&#39;</span></span>
<span class="line"><span style="color:#A6ACCD;">)comment &#39;学生表&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO student (name, no) VALUES (&#39;黛绮丝&#39;, &#39;2000100101&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO student (name, no) VALUES (&#39;谢逊&#39;, &#39;2000100102&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO student (name, no) VALUES (&#39;殷天正&#39;, &#39;2000100103&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO student (name, no) VALUES (&#39;韦一笑&#39;, &#39;2000100104&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">create table course(</span></span>
<span class="line"><span style="color:#A6ACCD;">    id int auto_increment comment &#39;主键ID&#39; primary key,</span></span>
<span class="line"><span style="color:#A6ACCD;">    name varchar(10) null comment &#39;课程名称&#39;</span></span>
<span class="line"><span style="color:#A6ACCD;">)comment &#39;课程表&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO course (name) VALUES (&#39;Java&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO course (name) VALUES (&#39;PHP&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO course (name) VALUES (&#39;MySQL&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO course (name) VALUES (&#39;Hadoop&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">create table student_course(</span></span>
<span class="line"><span style="color:#A6ACCD;">    id int auto_increment comment &#39;主键&#39; primary key,</span></span>
<span class="line"><span style="color:#A6ACCD;">    studentid int not null comment &#39;学生ID&#39;,</span></span>
<span class="line"><span style="color:#A6ACCD;">    courseid  int not null comment &#39;课程ID&#39;,</span></span>
<span class="line"><span style="color:#A6ACCD;">    constraint fk_courseid foreign key (courseid) references course (id),</span></span>
<span class="line"><span style="color:#A6ACCD;">    constraint fk_studentid foreign key (studentid) references student (id)</span></span>
<span class="line"><span style="color:#A6ACCD;">)comment &#39;学生课程中间表&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO student_course (studentid, courseid) VALUES (1, 1);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO student_course (studentid, courseid) VALUES (1, 2);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO student_course (studentid, courseid) VALUES (1, 3);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO student_course (studentid, courseid) VALUES (2, 2);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO student_course (studentid, courseid) VALUES (2, 3);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO student_course (studentid, courseid) VALUES (3, 4);</span></span></code></pre></div><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 查询每个学生选修的课程(三表联查)，这个功能很多业务都在使用，为了简化操作，定义一个视图</span></span>
<span class="line"><span style="color:#A6ACCD;">select * from student s,student_course sc,course c</span></span>
<span class="line"><span style="color:#A6ACCD;">where s.id=sc.studentid and  sc.courseid=c.id;</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">create view tb_stu_course1 as</span></span>
<span class="line"><span style="color:#A6ACCD;">select s.name &#39;姓名&#39;,s.no &#39;学号&#39;,c.name &#39;课程名&#39; </span></span>
<span class="line"><span style="color:#A6ACCD;">from student s,student_course sc,course c</span></span>
<span class="line"><span style="color:#A6ACCD;">where s.id=sc.studentid and  sc.courseid=c.id;</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">-- 进行查询</span></span>
<span class="line"><span style="color:#A6ACCD;">select * from tb_stu_course1;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220128120142606.png" alt="image-20220128120142606" style="zoom:80%;"><h2 id="存储过程-1" tabindex="-1">存储过程 <a class="header-anchor" href="#存储过程-1" aria-label="Permalink to &quot;存储过程&quot;">​</a></h2><blockquote><p>存储过程是事先经过编译并存储在数据库中的一段 SQL 语句的集合，调用存储过程可以简化应用开发人员的很多工作，减少数据在数据 库和应用服务器之间的传输，对于提高数据处理的效率是有好处的。</p></blockquote><p>存储过程思想上很简单，<strong>就是数据库 SQL 语言层面的代码封装与重用</strong>。</p><blockquote><ul><li><strong>封装，复用</strong> ---&gt; 可以把某一业务SQL封装在存储过程中，需要用到的时候直接调用即可。</li><li><strong>可以接收参数，也可以返回数据</strong> ---&gt; 再存储过程中，可以传递参数，也可以接收返回值。</li><li><strong>减少网络交互，效率提升</strong>----&gt; 如果涉及到多条SQL，每执行一次都是一次网络传输。</li><li>而如果封装在存储过程中，我们<strong>只需要网络交互一次可能就可以了</strong>。</li></ul></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209220942975.png" alt="image-20220922094208854" style="zoom:80%;"><blockquote><p>一般情况下，可能会出现存储过程中传入中文参数的情况，例如某个存储过程根据用户的 名字查找该用户的信息，传入的参数值可能是中文。这时需要在定义存储过程的时候，在后面加 上 character set gbk,不然调用存储过程使用中文参数会出错，比如定义 userInfo 存储过程，代码 如下：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">PROCEDURE</span><span style="color:#A6ACCD;"> useInfo(</span><span style="color:#F78C6C;">IN</span><span style="color:#A6ACCD;"> u_name </span><span style="color:#C792EA;">VARCHAR</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">50</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">character</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">set</span><span style="color:#A6ACCD;"> gbk, </span><span style="color:#F78C6C;">OUT</span><span style="color:#A6ACCD;"> u_age </span><span style="color:#C792EA;">INT</span><span style="color:#A6ACCD;">)</span></span></code></pre></div></blockquote><h3 id="基本语法⭐" tabindex="-1">基本语法⭐ <a class="header-anchor" href="#基本语法⭐" aria-label="Permalink to &quot;基本语法⭐&quot;">​</a></h3><h4 id="创建和调用" tabindex="-1">创建和调用 <a class="header-anchor" href="#创建和调用" aria-label="Permalink to &quot;创建和调用&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 创建存储过程</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">procedure</span><span style="color:#A6ACCD;"> 存储过程名(参数列表)</span></span>
<span class="line"><span style="color:#F78C6C;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">   存储过程体（一组合法的SQL语句）</span></span>
<span class="line"><span style="color:#F78C6C;">end</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 调用存储过程</span></span>
<span class="line"><span style="color:#F78C6C;">call</span><span style="color:#A6ACCD;"> 存储过程名(参数列表)</span></span></code></pre></div><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 创建存储过程示例</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">procedure</span><span style="color:#A6ACCD;"> p1</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#F78C6C;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> emp;</span></span>
<span class="line"><span style="color:#F78C6C;">end</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 调用存储过程</span></span>
<span class="line"><span style="color:#F78C6C;">call</span><span style="color:#A6ACCD;"> p1</span><span style="color:#89DDFF;">()</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209220947143.png" alt="image-20220922094713036" style="zoom:80%;"><h4 id="查看和删除" tabindex="-1">查看和删除 <a class="header-anchor" href="#查看和删除" aria-label="Permalink to &quot;查看和删除&quot;">​</a></h4><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 查看数据库中有没有存储过程函数，最后的是数据库名</span></span>
<span class="line"><span style="color:#A6ACCD;">select * from information_schema.ROUTINES where ROUTINE_SCHEMA=&#39;itcast&#39;;</span></span></code></pre></div><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 查看创建SQL</span></span>
<span class="line"><span style="color:#A6ACCD;">show create procedure p1;</span></span></code></pre></div><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 删除存储过程</span></span>
<span class="line"><span style="color:#A6ACCD;">drop procedure if exists 存储过程名;</span></span></code></pre></div><blockquote><p>注意: <strong>在命令行中，执行创建存储过程的SQL时，需要通过关键字 delimiter 指定SQL语句的结束符。因为命令行遇到分号会自动结束，此时就需要定义自动结束符加在end后delimiter $</strong></p></blockquote><h4 id="变量" tabindex="-1">变量 <a class="header-anchor" href="#变量" aria-label="Permalink to &quot;变量&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 变量: 局部变量</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 声明 - declare</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 赋值 -</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">procedure</span><span style="color:#A6ACCD;"> p2</span><span style="color:#89DDFF;">()</span></span>
<span class="line"><span style="color:#F78C6C;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">declare</span><span style="color:#A6ACCD;"> stu_count </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#A6ACCD;">; # 声明局部变量，需要用declare进行声明</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">into</span><span style="color:#A6ACCD;"> stu_count </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> student; # 将count(</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;">)结果赋值给局部变量</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> stu_count; # 查询结果</span></span>
<span class="line"><span style="color:#F78C6C;">end</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F78C6C;">call</span><span style="color:#A6ACCD;"> p2</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><h3 id="条件判断" tabindex="-1">条件判断 <a class="header-anchor" href="#条件判断" aria-label="Permalink to &quot;条件判断&quot;">​</a></h3><h4 id="if" tabindex="-1">if <a class="header-anchor" href="#if" aria-label="Permalink to &quot;if&quot;">​</a></h4><blockquote><p>在if条件判断的结构中，ELSE IF 结构可以有多个，也可以没有。 ELSE结构可以有，也可以没有</p></blockquote><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">create procedure p5(...)</span></span>
<span class="line"><span style="color:#A6ACCD;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    if 条件1 then</span></span>
<span class="line"><span style="color:#A6ACCD;">        ...</span></span>
<span class="line"><span style="color:#A6ACCD;">    elseif 条件2 then  -- 可选</span></span>
<span class="line"><span style="color:#A6ACCD;">        ...</span></span>
<span class="line"><span style="color:#A6ACCD;">    else    -- 可选</span></span>
<span class="line"><span style="color:#A6ACCD;">        ...</span></span>
<span class="line"><span style="color:#A6ACCD;">    end if;</span></span>
<span class="line"><span style="color:#A6ACCD;">end;</span></span></code></pre></div><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- if else</span></span>
<span class="line"><span style="color:#A6ACCD;">create procedure p4()</span></span>
<span class="line"><span style="color:#A6ACCD;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    declare score int default 58;</span></span>
<span class="line"><span style="color:#A6ACCD;">    declare result varchar(10);</span></span>
<span class="line"><span style="color:#A6ACCD;">    if score &gt;=85 then</span></span>
<span class="line"><span style="color:#A6ACCD;">        set result := &#39;优秀&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">    elseif score &gt;= 60 then</span></span>
<span class="line"><span style="color:#A6ACCD;">        set result := &#39;及格&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">    else</span></span>
<span class="line"><span style="color:#A6ACCD;">        set result := &#39;不及格&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">    end if;</span></span>
<span class="line"><span style="color:#A6ACCD;">    select result;</span></span>
<span class="line"><span style="color:#A6ACCD;">end;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 调用执行</span></span>
<span class="line"><span style="color:#A6ACCD;">call p4();</span></span></code></pre></div><blockquote><p>上述的需求我们虽然已经实现了，但是也存在一些问题，比如：score 分数我们是在存储过程中定义死的，而且最终计算出来的分数等级，我们也仅仅是最终查询展示出来而已。</p></blockquote><blockquote><p>那么我们能不能，把score分数动态的传递进来，计算出来的分数等级是否可以作为返回值返回呢？答案是肯定的，我们可以通过接下来所讲解的 参数 来解决上述的问题。</p></blockquote><h4 id="case" tabindex="-1">case <a class="header-anchor" href="#case" aria-label="Permalink to &quot;case&quot;">​</a></h4><p>语法一</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">case case_value</span></span>
<span class="line"><span style="color:#A6ACCD;">    when value1 then SQL1;</span></span>
<span class="line"><span style="color:#A6ACCD;">    when value2 then SQL2;</span></span>
<span class="line"><span style="color:#A6ACCD;">    else SQL3;</span></span>
<span class="line"><span style="color:#A6ACCD;">end case ;</span></span></code></pre></div><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">create procedure b2(in result varchar(30))</span></span>
<span class="line"><span style="color:#A6ACCD;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    case result</span></span>
<span class="line"><span style="color:#A6ACCD;">        when  1  then set result := &#39;success&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">        when  0  then set result := &#39;fail&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">        else  set result := &#39;none&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">    end case ;</span></span>
<span class="line"><span style="color:#A6ACCD;">    select concat(&#39;您的结果是：&#39;,result);</span></span>
<span class="line"><span style="color:#A6ACCD;">end;</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">call b2(1);</span></span></code></pre></div><p>语法二</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">case </span></span>
<span class="line"><span style="color:#A6ACCD;">    when 条件1 then SQL1;</span></span>
<span class="line"><span style="color:#A6ACCD;">    when 条件2 then SQL2;</span></span>
<span class="line"><span style="color:#A6ACCD;">    else SQL3;</span></span>
<span class="line"><span style="color:#A6ACCD;">end case ;</span></span></code></pre></div><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- case</span></span>
<span class="line"><span style="color:#A6ACCD;">create procedure p7(in month int)</span></span>
<span class="line"><span style="color:#A6ACCD;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    declare result varchar(10);</span></span>
<span class="line"><span style="color:#A6ACCD;">    case</span></span>
<span class="line"><span style="color:#A6ACCD;">        when month &gt;=1 and month &lt;=3 then</span></span>
<span class="line"><span style="color:#A6ACCD;">            set result := &#39;第一季度&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">        when month &gt;=4 and month &lt;=6 then</span></span>
<span class="line"><span style="color:#A6ACCD;">            set result := &#39;第二季度&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">        when month &gt;=7 and month &lt;=9 then</span></span>
<span class="line"><span style="color:#A6ACCD;">            set result := &#39;第三季度&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">        when month &gt;=10 and month &lt;=12 then</span></span>
<span class="line"><span style="color:#A6ACCD;">            set result := &#39;第四季度&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">        else</span></span>
<span class="line"><span style="color:#A6ACCD;">            set result :=&#39;非法参数&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">    end case ;</span></span>
<span class="line"><span style="color:#A6ACCD;">    select concat(&#39;你输入的月份：&#39;,month,&#39;，所属的季度为&#39;,result) &#39;result&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">end;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 调用</span></span>
<span class="line"><span style="color:#A6ACCD;">call p7(12);</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221043234.png" alt="image-20220922104313126" style="zoom:80%;"><h3 id="存储过程参数⭐" tabindex="-1">存储过程参数⭐ <a class="header-anchor" href="#存储过程参数⭐" aria-label="Permalink to &quot;存储过程参数⭐&quot;">​</a></h3><h4 id="语法" tabindex="-1">语法 <a class="header-anchor" href="#语法" aria-label="Permalink to &quot;语法&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220128153422860.png" alt="image-20220128153422860" style="zoom:80%;"><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">create procedure 存储过程名(in/out/inout 参数名 参数类型)</span></span>
<span class="line"><span style="color:#A6ACCD;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    SQL语句;</span></span>
<span class="line"><span style="color:#A6ACCD;">end;</span></span></code></pre></div><h4 id="示例" tabindex="-1">示例 <a class="header-anchor" href="#示例" aria-label="Permalink to &quot;示例&quot;">​</a></h4><p>根据传入参数score，判定当前分数对应的分数等级，并返回。</p><p>① score &gt;= 85分，等级为优秀。</p><p>② score &gt;= 60分 且 score &lt; 85分，等级为及格。</p><p>③ score &lt; 60分，等级为不及格。</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- in:传入参数,out：返回值,inout:既作为传入参数也作为返回值</span></span>
<span class="line"><span style="color:#A6ACCD;">create procedure p5(in score int,out result varchar(10))</span></span>
<span class="line"><span style="color:#A6ACCD;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    if score &gt;=85 then</span></span>
<span class="line"><span style="color:#A6ACCD;">        set result := &#39;优秀&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">    elseif score &gt;= 60 then</span></span>
<span class="line"><span style="color:#A6ACCD;">        set result := &#39;及格&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">    else</span></span>
<span class="line"><span style="color:#A6ACCD;">        set result := &#39;不及格&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">    end if;</span></span>
<span class="line"><span style="color:#A6ACCD;">end;</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">-- 将结果返回给res</span></span>
<span class="line"><span style="color:#A6ACCD;">call p5(68,@res);</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 查询结果</span></span>
<span class="line"><span style="color:#A6ACCD;">select @res &#39;结果&#39;;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221039057.png" alt="image-20220922103940941" style="zoom:80%;"><p>将传入的 200分制的分数,进行换算,换算成百分制 , 然后返回。</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 将传入的200分换算成百分制inout</span></span>
<span class="line"><span style="color:#A6ACCD;">create procedure p6(inout score double)</span></span>
<span class="line"><span style="color:#A6ACCD;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    set score := score*0.5;</span></span>
<span class="line"><span style="color:#A6ACCD;">end;</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">-- 将结果返回给res</span></span>
<span class="line"><span style="color:#A6ACCD;">set @score=78;</span></span>
<span class="line"><span style="color:#A6ACCD;">call p6(@score);</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 查询结果</span></span>
<span class="line"><span style="color:#A6ACCD;">select @score &#39;结果&#39;;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221041203.png" alt="image-20220922104138092" style="zoom:80%;"><h3 id="循环" tabindex="-1">循环 <a class="header-anchor" href="#循环" aria-label="Permalink to &quot;循环&quot;">​</a></h3><h4 id="while" tabindex="-1">while <a class="header-anchor" href="#while" aria-label="Permalink to &quot;while&quot;">​</a></h4><blockquote><p>while 循环是有条件的循环控制语句。满足条件后，再执行循环体中的SQL语句</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221044048.png" alt="image-20220922104439902" style="zoom:80%;"><p>示例</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- A. 定义局部变量, 记录累加之后的值; </span></span>
<span class="line"><span style="color:#A6ACCD;">-- B. 每循环一次, 就会对n进行减1 , 如果n减到0, 则退出循环</span></span>
<span class="line"><span style="color:#A6ACCD;">create procedure p8(in n int)</span></span>
<span class="line"><span style="color:#A6ACCD;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    declare total int default 0;</span></span>
<span class="line"><span style="color:#A6ACCD;">    while n&gt;0 do</span></span>
<span class="line"><span style="color:#A6ACCD;">        set total := total + n;</span></span>
<span class="line"><span style="color:#A6ACCD;">        set n := n - 1;</span></span>
<span class="line"><span style="color:#A6ACCD;">    end while;</span></span>
<span class="line"><span style="color:#A6ACCD;">    select total;</span></span>
<span class="line"><span style="color:#A6ACCD;">end;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 调用，55</span></span>
<span class="line"><span style="color:#A6ACCD;">call p8(10);</span></span></code></pre></div><h4 id="repeat⭐" tabindex="-1">repeat⭐ <a class="header-anchor" href="#repeat⭐" aria-label="Permalink to &quot;repeat⭐&quot;">​</a></h4><blockquote><p>repeat是有条件的循环控制语句, 当满足until声明的条件的时候，则退出循环</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221046553.png" alt="image-20220922104638404" style="zoom:80%;"><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- A. 定义局部变量, 记录累加之后的值; </span></span>
<span class="line"><span style="color:#A6ACCD;">-- B. 每循环一次, 就会对n进行-1 , 如果n减到0, 则退出循环</span></span>
<span class="line"><span style="color:#A6ACCD;">create procedure p9(in n int)</span></span>
<span class="line"><span style="color:#A6ACCD;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    declare total int default 0;</span></span>
<span class="line"><span style="color:#A6ACCD;">    repeat</span></span>
<span class="line"><span style="color:#A6ACCD;">        set total := total + n;</span></span>
<span class="line"><span style="color:#A6ACCD;">        set n := n - 1;</span></span>
<span class="line"><span style="color:#A6ACCD;">    until n &lt;= 0</span></span>
<span class="line"><span style="color:#A6ACCD;">    end repeat ;</span></span>
<span class="line"><span style="color:#A6ACCD;">    select total;</span></span>
<span class="line"><span style="color:#A6ACCD;">end;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 调用</span></span>
<span class="line"><span style="color:#A6ACCD;">call p9(100);</span></span></code></pre></div><p>创建函数</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">procedure</span><span style="color:#A6ACCD;"> p10(</span><span style="color:#F78C6C;">in</span><span style="color:#A6ACCD;"> n </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#F78C6C;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">	</span><span style="color:#F78C6C;">repeat</span></span>
<span class="line"><span style="color:#A6ACCD;">      </span><span style="color:#F78C6C;">insert into</span><span style="color:#A6ACCD;"> author </span><span style="color:#F78C6C;">values</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#82AAFF;">concat</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">刘备</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">,n),</span><span style="color:#82AAFF;">concat</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">中国</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">,n));</span></span>
<span class="line"><span style="color:#A6ACCD;">			</span><span style="color:#F78C6C;">set</span><span style="color:#A6ACCD;"> n :</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> n </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    until n </span><span style="color:#89DDFF;">&lt;=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">end</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">repeat</span><span style="color:#A6ACCD;"> ;</span></span>
<span class="line"><span style="color:#F78C6C;">end</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>调用函数</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 不得不说数据量一大插入数据真是慢</span></span>
<span class="line"><span style="color:#F78C6C;">call</span><span style="color:#A6ACCD;"> p10(</span><span style="color:#F78C6C;">9900000</span><span style="color:#A6ACCD;">)</span></span></code></pre></div><p>查询数量</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> author;</span></span></code></pre></div><p>创建存储函数来批量插入数据</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">procedure</span><span style="color:#A6ACCD;"> p11(</span><span style="color:#F78C6C;">in</span><span style="color:#A6ACCD;"> n </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#F78C6C;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">start transaction</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">		</span><span style="color:#F78C6C;">repeat</span></span>
<span class="line"><span style="color:#A6ACCD;">      </span><span style="color:#F78C6C;">insert into</span><span style="color:#A6ACCD;"> author </span><span style="color:#F78C6C;">values</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#82AAFF;">concat</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">刘备</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">,n),</span><span style="color:#82AAFF;">concat</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">中国</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">,n));</span></span>
<span class="line"><span style="color:#A6ACCD;">			</span><span style="color:#F78C6C;">set</span><span style="color:#A6ACCD;"> n :</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> n </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    until n </span><span style="color:#89DDFF;">&lt;=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">end</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">repeat</span><span style="color:#A6ACCD;"> ;</span></span>
<span class="line"><span style="color:#A6ACCD;">		</span><span style="color:#F78C6C;">commit</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#F78C6C;">end</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>只花了300多秒</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">call</span><span style="color:#A6ACCD;"> p11(</span><span style="color:#F78C6C;">9900000</span><span style="color:#A6ACCD;">)</span></span></code></pre></div><h4 id="loop" tabindex="-1">loop <a class="header-anchor" href="#loop" aria-label="Permalink to &quot;loop&quot;">​</a></h4><blockquote><p>LOOP 实现简单的循环，如果不在SQL逻辑中增加退出循环的条件，可以用其来实现简单的死循环。LOOP可以配合一下两个语句使用：</p></blockquote><ul><li><p>LEAVE ：配合循环使用，退出循环。</p></li><li><p>ITERATE：必须用在循环中，作用是跳过当前循环剩下的语句，直接进入下一次循环。</p></li></ul><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221048537.png" alt="image-20220922104846428" style="zoom:80%;"><blockquote><p>上述语法中出现的 begin_label，end_label，label 指的都是我们所自定义的标记。</p></blockquote><p>示例</p><p>计算从1累加到n的值，n为传入的参数值。</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- A. 定义局部变量, 记录累加之后的值; </span></span>
<span class="line"><span style="color:#A6ACCD;">-- B. 每循环一次, 就会对n进行-1 , 如果n减到0, 则退出循环 ----&gt; leave xx</span></span>
<span class="line"><span style="color:#A6ACCD;">create procedure p10(in n int)</span></span>
<span class="line"><span style="color:#A6ACCD;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    declare total int default 0;</span></span>
<span class="line"><span style="color:#A6ACCD;">    sum:loop</span></span>
<span class="line"><span style="color:#A6ACCD;">        if n&lt;=0 then</span></span>
<span class="line"><span style="color:#A6ACCD;">            leave sum;</span></span>
<span class="line"><span style="color:#A6ACCD;">        end if;</span></span>
<span class="line"><span style="color:#A6ACCD;">        set total := total + n;</span></span>
<span class="line"><span style="color:#A6ACCD;">        set n := n - 1;</span></span>
<span class="line"><span style="color:#A6ACCD;">    end loop sum;</span></span>
<span class="line"><span style="color:#A6ACCD;">    select total;</span></span>
<span class="line"><span style="color:#A6ACCD;">end;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 调用</span></span>
<span class="line"><span style="color:#A6ACCD;">call p10(10000);</span></span></code></pre></div><p>计算从1到n之间的偶数累加的值，n为传入的参数值</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- A. 定义局部变量, 记录累加之后的值; </span></span>
<span class="line"><span style="color:#A6ACCD;">-- B. 每循环一次, 就会对n进行-1 , 如果n减到0, 则退出循环 ----&gt; leave xx </span></span>
<span class="line"><span style="color:#A6ACCD;">-- C. 如果当次累加的数据是奇数, 则直接进入下一次循环. --------&gt; iterate xx</span></span>
<span class="line"><span style="color:#A6ACCD;">create procedure p11(in n int)</span></span>
<span class="line"><span style="color:#A6ACCD;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    declare total int default 0;</span></span>
<span class="line"><span style="color:#A6ACCD;">    sum:loop</span></span>
<span class="line"><span style="color:#A6ACCD;">        if n&lt;=0 then</span></span>
<span class="line"><span style="color:#A6ACCD;">            leave sum;</span></span>
<span class="line"><span style="color:#A6ACCD;">        end if;</span></span>
<span class="line"><span style="color:#A6ACCD;">        if n%2 = 1 then</span></span>
<span class="line"><span style="color:#A6ACCD;">            set n:=n-1;</span></span>
<span class="line"><span style="color:#A6ACCD;">            iterate sum;</span></span>
<span class="line"><span style="color:#A6ACCD;">        end if;</span></span>
<span class="line"><span style="color:#A6ACCD;">        set total := total + n;</span></span>
<span class="line"><span style="color:#A6ACCD;">        set n := n - 1;</span></span>
<span class="line"><span style="color:#A6ACCD;">    end loop sum;</span></span>
<span class="line"><span style="color:#A6ACCD;">    select total;</span></span>
<span class="line"><span style="color:#A6ACCD;">end;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 调用</span></span>
<span class="line"><span style="color:#A6ACCD;">call p11(10); -- 30</span></span></code></pre></div><h3 id="游标" tabindex="-1">游标 <a class="header-anchor" href="#游标" aria-label="Permalink to &quot;游标&quot;">​</a></h3><blockquote><p>游标（CURSOR）是<strong>用来存储查询结果集的数据类型 , 在存储过程和函数中可以使用游标对结果集进行循环的处理</strong>。<strong>游标的使用包括游标 的声明、OPEN、FETCH 和 CLOSE</strong>，其语法分别如下。</p></blockquote><h4 id="游标语法" tabindex="-1">游标语法 <a class="header-anchor" href="#游标语法" aria-label="Permalink to &quot;游标语法&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221028077.png" alt="image-20220922102818951" style="zoom:80%;"><h4 id="条件处理函数" tabindex="-1">条件处理函数 <a class="header-anchor" href="#条件处理函数" aria-label="Permalink to &quot;条件处理函数&quot;">​</a></h4><blockquote><p>条件处理程序（Handler）可以用来定义在流程控制结构执行过程中遇到问题时相应的处理步骤。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221030059.png" alt="image-20220922103036938" style="zoom:80%;"><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 声明循环结束条件,报错状态码为02000时退出循环，不加这句就会有02000的报错</span></span>
<span class="line"><span style="color:#A6ACCD;">declare exit handler for SQLSTATE &#39;02000&#39; close u_cursor;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 作用同上</span></span>
<span class="line"><span style="color:#A6ACCD;">declare exit handler for not found close u_cursor;</span></span></code></pre></div><h4 id="游标示例" tabindex="-1">游标示例 <a class="header-anchor" href="#游标示例" aria-label="Permalink to &quot;游标示例&quot;">​</a></h4><blockquote><p>根据传入的参数uage，来查询用户表tb_user中，所有的用户年龄小于等于uage的用户姓名（name）和专业（profession），并将用户的姓名和专业插入到所创建的一张新表(id,name,profession)中。</p></blockquote><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 游标</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 1、声明游标，存储查询结果集、2、创建表结构</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 3、开启游标、获取游标中的记录 4、插入数据到新表中</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 5、关闭游标</span></span>
<span class="line"><span style="color:#A6ACCD;">create procedure a1(in uage int)</span></span>
<span class="line"><span style="color:#A6ACCD;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    -- 要先声明变量，在声明游标</span></span>
<span class="line"><span style="color:#A6ACCD;">    -- 插入数据时使用</span></span>
<span class="line"><span style="color:#A6ACCD;">    declare uname varchar(100);</span></span>
<span class="line"><span style="color:#A6ACCD;">    declare upro varchar(100);</span></span>
<span class="line"><span style="color:#A6ACCD;">    -- 1、声明游标，存储查询结果集</span></span>
<span class="line"><span style="color:#A6ACCD;">    declare u_cursor cursor for select name,profession from tb_user1 where age &lt;= uage;</span></span>
<span class="line"><span style="color:#A6ACCD;">    -- 声明循环结束条件,报错状态码为02000时退出循环，不加这句就会有02000的报错</span></span>
<span class="line"><span style="color:#A6ACCD;">    declare exit handler for SQLSTATE &#39;02000&#39; close u_cursor;</span></span>
<span class="line"><span style="color:#A6ACCD;">   -- 作用同上</span></span>
<span class="line"><span style="color:#A6ACCD;">   -- declare exit handler for not found close u_cursor;</span></span>
<span class="line"><span style="color:#A6ACCD;">    -- 2、创建表结构</span></span>
<span class="line"><span style="color:#A6ACCD;">    create table if not exists tb_user_pro(</span></span>
<span class="line"><span style="color:#A6ACCD;">        id int primary key auto_increment,</span></span>
<span class="line"><span style="color:#A6ACCD;">        name varchar(100),</span></span>
<span class="line"><span style="color:#A6ACCD;">        profession varchar(100)</span></span>
<span class="line"><span style="color:#A6ACCD;">    );</span></span>
<span class="line"><span style="color:#A6ACCD;">    -- 3、开启游标</span></span>
<span class="line"><span style="color:#A6ACCD;">    open u_cursor;</span></span>
<span class="line"><span style="color:#A6ACCD;">    while true do</span></span>
<span class="line"><span style="color:#A6ACCD;">        fetch u_cursor into uname,upro;</span></span>
<span class="line"><span style="color:#A6ACCD;">        insert into tb_user_pro values (null,uname,upro);</span></span>
<span class="line"><span style="color:#A6ACCD;">    end while;</span></span>
<span class="line"><span style="color:#A6ACCD;">    close u_cursor;</span></span>
<span class="line"><span style="color:#A6ACCD;">end;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 调用</span></span>
<span class="line"><span style="color:#A6ACCD;">call a1(40);</span></span></code></pre></div><h3 id="存储函数" tabindex="-1">存储函数 <a class="header-anchor" href="#存储函数" aria-label="Permalink to &quot;存储函数&quot;">​</a></h3><p>存储函数是有返回值的存储过程，存储函数的参数只能是IN类型的。语法</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">create function 存储函数名(参数列表)</span></span>
<span class="line"><span style="color:#A6ACCD;">returns 数据类型 单词</span></span>
<span class="line"><span style="color:#A6ACCD;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    SQL语句</span></span>
<span class="line"><span style="color:#A6ACCD;">    return ...;</span></span>
<span class="line"><span style="color:#A6ACCD;">end;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 调用</span></span>
<span class="line"><span style="color:#A6ACCD;">select f1(100);</span></span></code></pre></div><p>上面单词可选</p><ul><li>deterministic：相同的输入参数总是产生相同的结果</li><li>no sql：不包含SQL语句</li><li>reads sql data：包含读取数据的语句，但不包含写入数据的语句。</li></ul><p>示例</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 用的较少，语法和存储过程很像，功能也很像</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 存储函数，只能是in类型</span></span>
<span class="line"><span style="color:#A6ACCD;">create function f1(n int)</span></span>
<span class="line"><span style="color:#A6ACCD;">returns int deterministic</span></span>
<span class="line"><span style="color:#A6ACCD;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    declare total int default 0;</span></span>
<span class="line"><span style="color:#A6ACCD;">    while n&gt;0 do</span></span>
<span class="line"><span style="color:#A6ACCD;">       set total := total + n;</span></span>
<span class="line"><span style="color:#A6ACCD;">       set n := n - 1;</span></span>
<span class="line"><span style="color:#A6ACCD;">    end while;</span></span>
<span class="line"><span style="color:#A6ACCD;">    return total;</span></span>
<span class="line"><span style="color:#A6ACCD;">end;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 调用</span></span>
<span class="line"><span style="color:#A6ACCD;">select f1(100);</span></span></code></pre></div><h2 id="触发器" tabindex="-1">触发器 <a class="header-anchor" href="#触发器" aria-label="Permalink to &quot;触发器&quot;">​</a></h2><blockquote><p><strong>触发器是与表有关的数据库对象，指在 insert/update/delete 之前或之后，触发并执行触发器中定义的SQL语句集合。触发器的这种特性可以协助应用在数据库端确保数据的完整性 , 日志记录 , 数据校验等操作</strong> 。</p></blockquote><blockquote><p><strong>使用别名 OLD 和 NEW 来引用触发器中发生变化的记录内容，这与其他的数据库是相似的。</strong></p><p><strong>现在触发器还只支持行级触发，不支持语句级触发</strong>。</p><p><strong>行级触发器：修改几行就触发几次，如批量修改的话就会批量的触发</strong></p><p><strong>语句级触发器：无论修改多少行只触发一次</strong></p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209212158650.png" alt="image-20220921215825495" style="zoom:80%;"><h3 id="基本语法-2" tabindex="-1">基本语法 <a class="header-anchor" href="#基本语法-2" aria-label="Permalink to &quot;基本语法&quot;">​</a></h3><h4 id="创建触发器" tabindex="-1">创建触发器 <a class="header-anchor" href="#创建触发器" aria-label="Permalink to &quot;创建触发器&quot;">​</a></h4><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 插入数据的触发器</span></span>
<span class="line"><span style="color:#A6ACCD;">create trigger triggerName</span></span>
<span class="line"><span style="color:#A6ACCD;">after/before insert/update/delete -- 在增删改前后执行</span></span>
<span class="line"><span style="color:#A6ACCD;">on tableName(要操作的表) for each row -- 行级触发器</span></span>
<span class="line"><span style="color:#A6ACCD;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    trigger_stmt;</span></span>
<span class="line"><span style="color:#A6ACCD;">end;</span></span></code></pre></div><h4 id="查看触发器" tabindex="-1">查看触发器 <a class="header-anchor" href="#查看触发器" aria-label="Permalink to &quot;查看触发器&quot;">​</a></h4><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 查看触发器</span></span>
<span class="line"><span style="color:#A6ACCD;">show triggers ;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209212224897.png" alt="image-20220921222427772" style="zoom:80%;"><h4 id="删除触发器" tabindex="-1">删除触发器 <a class="header-anchor" href="#删除触发器" aria-label="Permalink to &quot;删除触发器&quot;">​</a></h4><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 删除触发器，如果没有指定数据库名，默认当前数据库</span></span>
<span class="line"><span style="color:#A6ACCD;">drop trigger 触发器名称;</span></span></code></pre></div><h3 id="实战演练⭐" tabindex="-1">实战演练⭐ <a class="header-anchor" href="#实战演练⭐" aria-label="Permalink to &quot;实战演练⭐&quot;">​</a></h3><h4 id="触发器作用表" tabindex="-1">触发器作用表 <a class="header-anchor" href="#触发器作用表" aria-label="Permalink to &quot;触发器作用表&quot;">​</a></h4><p>通过触发器记录dept表的数据变更日志，将变更日志插入到日志表dept_logs中, 包含增加, 修改 , 删除 ;</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 创建触发器启动时进行插入的表</span></span>
<span class="line"><span style="color:#A6ACCD;">create table dept_logs(</span></span>
<span class="line"><span style="color:#A6ACCD;">  id int(11) not null primary key auto_increment,</span></span>
<span class="line"><span style="color:#A6ACCD;">  operation varchar(20) not null comment &#39;操作类型, insert/update/delete&#39;,</span></span>
<span class="line"><span style="color:#A6ACCD;">  operate_time datetime not null comment &#39;操作时间&#39;,</span></span>
<span class="line"><span style="color:#A6ACCD;">  operate_id int(11) not null comment &#39;操作的ID&#39;,</span></span>
<span class="line"><span style="color:#A6ACCD;">  operate_params varchar(500) comment &#39;操作参数&#39;</span></span>
<span class="line"><span style="color:#A6ACCD;">)engine=innodb default charset=utf8;</span></span></code></pre></div><h4 id="插入操作触发器" tabindex="-1">插入操作触发器 <a class="header-anchor" href="#插入操作触发器" aria-label="Permalink to &quot;插入操作触发器&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">trigger</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">dept_insert_trigger</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 在dept表插入后激活触发器，行级触发器，每行都会触发一次</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">after</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">insert</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> dept for each </span><span style="color:#F78C6C;">row</span></span>
<span class="line"><span style="color:#F78C6C;">begin</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 往触发器插入数据</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">insert into</span><span style="color:#A6ACCD;"> dept_logs(id, operation, operate_time, operate_id, operate_params) </span><span style="color:#F78C6C;">VALUES</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 通过old和new关键字拿到插入前后的数据，(id和name是dept表的数据)</span></span>
<span class="line"><span style="color:#A6ACCD;">    (</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">insert</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">now</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;">,new.id,</span><span style="color:#82AAFF;">concat</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">插入的内容为:id:</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,new.id,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">,name:</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,new.name));</span></span>
<span class="line"><span style="color:#F78C6C;">end</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>插入数据，发现触发器表和原表都存在数据</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">insert into</span><span style="color:#A6ACCD;"> dept(id, </span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">values</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">高级部</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">);</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209212212863.png" alt="image-20220921221248748" style="zoom:80%;"><p>查看和删除触发器</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 查看触发器</span></span>
<span class="line"><span style="color:#A6ACCD;">show triggers ;</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">-- 删除触发器</span></span>
<span class="line"><span style="color:#A6ACCD;">drop trigger admin_insert_trigger;</span></span></code></pre></div><h4 id="更新操作触发器" tabindex="-1">更新操作触发器 <a class="header-anchor" href="#更新操作触发器" aria-label="Permalink to &quot;更新操作触发器&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 修改数据的触发器</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">trigger</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">dept_update_trigger</span></span>
<span class="line"><span style="color:#89DDFF;">     </span><span style="color:#676E95;font-style:italic;">-- 在dept表更新后激活触发器，行级触发器，每行都会触发一次</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">after</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">update</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> dept for each </span><span style="color:#F78C6C;">row</span></span>
<span class="line"><span style="color:#F78C6C;">begin</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 往触发器插入数据</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">insert into</span><span style="color:#A6ACCD;"> dept_logs(id, operation, operate_time, operate_id, operate_params) </span><span style="color:#F78C6C;">values</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 通过old和new关键字拿到插入前后的数据，(id和name是dept表的数据)</span></span>
<span class="line"><span style="color:#A6ACCD;">    (</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">update</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">now</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;">,new.id,</span></span>
<span class="line"><span style="color:#A6ACCD;">     </span><span style="color:#82AAFF;">concat</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">更新前的内容为</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">id:</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,old.id,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">name:</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,old.name,</span></span>
<span class="line"><span style="color:#A6ACCD;">            </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">,更新后的内容为</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">id:</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,new.id,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">name:</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,new.name));</span></span>
<span class="line"><span style="color:#F78C6C;">end</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>更新数据测试，成功更新</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">update dept set name=&#39;运营部&#39; where id = 4;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209212219043.png" alt="image-20220921221958921" style="zoom:80%;"><h4 id="删除操作触发器" tabindex="-1">删除操作触发器 <a class="header-anchor" href="#删除操作触发器" aria-label="Permalink to &quot;删除操作触发器&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">trigger</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">dept_delete_trigger</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 在dept表插入后激活触发器，行级触发器，每行都会触发一次</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">after</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">delete</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> dept for each </span><span style="color:#F78C6C;">row</span></span>
<span class="line"><span style="color:#F78C6C;">begin</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 往触发器插入数据</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">insert into</span><span style="color:#A6ACCD;"> dept_logs(id, operation, operate_time, operate_id, operate_params) </span><span style="color:#F78C6C;">VALUES</span></span>
<span class="line"><span style="color:#89DDFF;">    </span><span style="color:#676E95;font-style:italic;">-- 通过old拿到插入前后的数据，(id和name是dept表的数据)</span></span>
<span class="line"><span style="color:#A6ACCD;">    (</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">delete</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">now</span><span style="color:#89DDFF;">()</span><span style="color:#A6ACCD;">,old.id,</span><span style="color:#82AAFF;">concat</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">删除前的内容为:id:</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,old.id,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">,name:</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,old.name));</span></span>
<span class="line"><span style="color:#F78C6C;">end</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>删除数据,成功激活触发器</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">delete from dept where id = 7;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209212222479.png" alt="image-20220921222257342" style="zoom:80%;"><h1 id="变量-1" tabindex="-1">变量 <a class="header-anchor" href="#变量-1" aria-label="Permalink to &quot;变量&quot;">​</a></h1><p>在MySQL中变量分为三种类型: 系统变量、用户定义变量、局部变量。</p><p>MySQL服务重新启动之后，所设置的全局参数会失效，要想不失效，可以在 /etc/my.cnf 中配置</p><h2 id="系统变量" tabindex="-1">系统变量 <a class="header-anchor" href="#系统变量" aria-label="Permalink to &quot;系统变量&quot;">​</a></h2><blockquote><p>作用域：针对于所有会话（连接）有效，但不能跨重启</p></blockquote><h3 id="查看系统变量" tabindex="-1">查看系统变量 <a class="header-anchor" href="#查看系统变量" aria-label="Permalink to &quot;查看系统变量&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221024535.png" alt="image-20220922102444399" style="zoom:80%;"><h3 id="设置系统变量" tabindex="-1">设置系统变量 <a class="header-anchor" href="#设置系统变量" aria-label="Permalink to &quot;设置系统变量&quot;">​</a></h3><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">SET</span><span style="color:#A6ACCD;"> [ SESSION | GLOBAL ] 系统变量名 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> 值 ; </span></span>
<span class="line"><span style="color:#F78C6C;">SET</span><span style="color:#A6ACCD;"> @@[SESSION | GLOBAL]系统变量名 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> 值 ;</span></span></code></pre></div><blockquote><p>如果没有指定SESSION/GLOBAL，默认是SESSION，会话变量。</p><p>服务重新启动之后，所设置的全局参数会失效，要想不失效，可以在 /etc/my.cnf 中配置。</p><p>A. 全局变量(GLOBAL): 全局变量针对于所有的会话。</p><p>B. 会话变量(SESSION): 会话变量针对于单个会话，在另外一个会话窗口就不生效</p></blockquote><h3 id="演示示例" tabindex="-1">演示示例 <a class="header-anchor" href="#演示示例" aria-label="Permalink to &quot;演示示例&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221024793.png" alt="image-20220922102416639" style="zoom:80%;"><h2 id="用户自定义变量" tabindex="-1">用户自定义变量 <a class="header-anchor" href="#用户自定义变量" aria-label="Permalink to &quot;用户自定义变量&quot;">​</a></h2><blockquote><p>用户定义变量 是用户根据需要自己定义的变量，用户变量不用提前声明，在用的时候直接用 &quot;@变量名&quot; 使用就可以。其作用域为当前连接。</p></blockquote><h3 id="赋值和使用" tabindex="-1">赋值和使用 <a class="header-anchor" href="#赋值和使用" aria-label="Permalink to &quot;赋值和使用&quot;">​</a></h3><p>赋值时，可以使用 = ，也可以使用 :=</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221007639.png" alt="image-20220922100750506" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221008546.png" alt="image-20220922100800440" style="zoom:80%;"><p>使用</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221008748.png" alt="image-20220922100829641" style="zoom:80%;"><blockquote><p>注意: 用户定义的变量无需对其进行声明或初始化，只不过获取到的值为NULL</p></blockquote><h3 id="演示示例-1" tabindex="-1">演示示例 <a class="header-anchor" href="#演示示例-1" aria-label="Permalink to &quot;演示示例&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221009205.png" alt="image-20220922100931061" style="zoom:80%;"><h2 id="局部变量-常用" tabindex="-1">局部变量(常用) <a class="header-anchor" href="#局部变量-常用" aria-label="Permalink to &quot;局部变量(常用)&quot;">​</a></h2><blockquote><p>局部变量 是根据需要定义的在局部生效的变量，访问之前，需要DECLARE声明。可用作存储过程内的局部变量和输入参数，局部变量的范围是在其内声明的BEGIN ... END块。</p></blockquote><h3 id="声明局部变量" tabindex="-1">声明局部变量 <a class="header-anchor" href="#声明局部变量" aria-label="Permalink to &quot;声明局部变量&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221006794.png" alt="image-20220922100619657" style="zoom:80%;"><blockquote><p>变量类型就是数据库字段类型：INT、BIGINT、CHAR、VARCHAR、DATE、TIME等。</p></blockquote><h3 id="局部变量赋值" tabindex="-1">局部变量赋值 <a class="header-anchor" href="#局部变量赋值" aria-label="Permalink to &quot;局部变量赋值&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221004602.png" alt="image-20220922100425457" style="zoom:80%;"><h3 id="演示示例-2" tabindex="-1">演示示例 <a class="header-anchor" href="#演示示例-2" aria-label="Permalink to &quot;演示示例&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221006453.png" alt="image-20220922100602338" style="zoom:80%;"><h3 id="与用户变量区别" tabindex="-1">与用户变量区别 <a class="header-anchor" href="#与用户变量区别" aria-label="Permalink to &quot;与用户变量区别&quot;">​</a></h3><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">作用域			     定义位置		       语法</span></span>
<span class="line"><span style="color:#A6ACCD;">用户变量	当前会话		     会话的任何地方		加@符号，不用指定类型</span></span>
<span class="line"><span style="color:#A6ACCD;">局部变量	定义它的BEGIN END中 	</span><span style="color:#F78C6C;">BEGIN</span><span style="color:#A6ACCD;"> END的第一句话	一般不用加@,需要指定类型</span></span></code></pre></div><h1 id="锁⭐" tabindex="-1">锁⭐ <a class="header-anchor" href="#锁⭐" aria-label="Permalink to &quot;锁⭐&quot;">​</a></h1><h2 id="概述-1" tabindex="-1">概述 <a class="header-anchor" href="#概述-1" aria-label="Permalink to &quot;概述&quot;">​</a></h2><blockquote><p>锁是计算机<strong>协调多个进程或线程并发访问某一资源的机制</strong>。在数据库中，除传统的计算资源（CPU、RAM、I/O）的争用以外，数据也是 一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题，锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说，锁对数据库而言显得尤其重要，也更加复杂。<strong><code>解决并发访问时数据访问一致性，有效性的问题</code></strong></p></blockquote><p>MySQL中的锁，按照锁的粒度分，分为以下三类：</p><ul><li><p>全局锁：<code>锁定数据库中的所有表，加锁后整个数据库处于只读状态，性能较差，数据逻辑备份使用</code></p></li><li><p>表级锁：<code>每次操作锁住整张表，避免增删问题，锁定粒度大，发生锁冲突概率高(表锁、元数据锁、意向锁)</code></p></li><li><p>行级锁：<code>每次操作锁住对应的行数据，锁定粒度最小，发生锁冲突概率低(行锁，间隙锁，临建锁)</code></p></li></ul><h2 id="全局锁" tabindex="-1">全局锁 <a class="header-anchor" href="#全局锁" aria-label="Permalink to &quot;全局锁&quot;">​</a></h2><h3 id="全局锁概述" tabindex="-1">全局锁概述 <a class="header-anchor" href="#全局锁概述" aria-label="Permalink to &quot;全局锁概述&quot;">​</a></h3><blockquote><p>典型的使用场景是做<strong>全库的逻辑备份</strong>，对所有的表进行锁定，从而获取一致性视图，<strong>保证数据的完整性</strong>。</p></blockquote><blockquote><p>全局锁就是对整个数据库实例加锁，加锁后整个实例就处于<strong>只读状态</strong>，<strong>后续的DML的写语句，DDL语句，已经更新操作的事务提交语句都将被阻塞</strong>。注意：只能读，不能写</p></blockquote><p>没使用全局锁情况</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220410143151264.png" alt="image-20220410143151264" style="zoom:67%;"><p>使用全局锁情况</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220201154525026.png" alt="image-20220201154525026" style="zoom:80%;"><h3 id="数据库全局锁实现" tabindex="-1">数据库全局锁实现 <a class="header-anchor" href="#数据库全局锁实现" aria-label="Permalink to &quot;数据库全局锁实现&quot;">​</a></h3><h4 id="正常上锁" tabindex="-1">正常上锁 <a class="header-anchor" href="#正常上锁" aria-label="Permalink to &quot;正常上锁&quot;">​</a></h4><p>进入cmd</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">mysql </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456</span></span></code></pre></div><p>加上全局锁，此时其他窗口不能增删改，处于阻塞阶段</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">flush tables with read lock</span><span style="color:#89DDFF;">;</span></span></code></pre></div><p>进入另一个cmd，直接操作，不用进入mysql</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">mysqldump </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 myemployees </span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> D:</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">db01</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">sql</span></span></code></pre></div><p>在原cmd解锁</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">unlock tables</span><span style="color:#89DDFF;">;</span></span></code></pre></div><p>注意：在上锁期间，只能对数据库进行查询，不能进行增删改，数据库中加全局锁，是一个重的操作，存在以下问题</p><blockquote><ol><li>如果在主库上备份，那么在备份期间都不能执行更新，业务基本上就得停摆。</li><li>如果在从库上备份，那么在备份期间从库不能执行主库同步过来的二进制日志（binlog），<code>会导致主从延迟</code></li></ol></blockquote><h4 id="不加锁一致性⭐" tabindex="-1">不加锁一致性⭐ <a class="header-anchor" href="#不加锁一致性⭐" aria-label="Permalink to &quot;不加锁一致性⭐&quot;">​</a></h4><blockquote><p>在InnoDB引擎中，我们可以在备份时加上参数 --single-transaction 参数来完成不加锁的一致性数据备份。</p><p>在MySQL底层是通过快照读来实现的备份</p></blockquote><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">mysqldump </span><span style="color:#89DDFF;">--</span><span style="color:#A6ACCD;">single</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">transaction </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 myemployees </span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> D:</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">db02</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">sql</span></span></code></pre></div><h2 id="表级锁" tabindex="-1">表级锁 <a class="header-anchor" href="#表级锁" aria-label="Permalink to &quot;表级锁&quot;">​</a></h2><blockquote><p><strong>表级锁，每次操作锁住整张表。锁定粒度大，发生锁冲突的概率最高，并发度最低</strong>。应用在MyISAM、InnoDB、BDB等存储引擎中。</p></blockquote><p>对于表级锁，主要分为以下三类：</p><blockquote><p>1.<strong>表锁</strong></p><p>2.<strong>元数据锁（meta data lock，MDL）</strong></p><p>3.<strong>意向锁</strong></p></blockquote><h3 id="表锁" tabindex="-1">表锁 <a class="header-anchor" href="#表锁" aria-label="Permalink to &quot;表锁&quot;">​</a></h3><blockquote><p><strong>读锁不会阻塞其他客户端的读，但是会阻塞写。写锁既会阻塞其他客户端的读，又会阻塞其他客户端的写</strong></p></blockquote><p>对于表锁，分为两类：</p><blockquote><p>1.<strong>表共享读锁（read lock）</strong></p><p>2.<strong>表独占写锁（write lock）</strong></p></blockquote><blockquote><p>1.<strong>加锁：lock tables 表名... read/write</strong></p><p>2.<strong>释放锁：unlock tables / 客户端断开连接</strong></p></blockquote><h4 id="表共享读锁" tabindex="-1">表共享读锁 <a class="header-anchor" href="#表共享读锁" aria-label="Permalink to &quot;表共享读锁&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221428072.png" alt="image-20220922142812893" style="zoom:80%;"><blockquote><p>左侧为客户端一，对指定表加了读锁，不会影响右侧客户端二的读，但是会阻塞右侧客户端的写。</p></blockquote><p>客户端一</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 客户端一加锁</span></span>
<span class="line"><span style="color:#A6ACCD;">lock tables boys read ;</span></span>
<span class="line"><span style="color:#A6ACCD;">select * from boys;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 进行更新</span></span>
<span class="line"><span style="color:#A6ACCD;">-- [HY000][1099] Table &#39;boys&#39; was locked with a READ lock and can&#39;t be updated</span></span>
<span class="line"><span style="color:#A6ACCD;">update boys set boyName = &#39;王瑞&#39; where id=1;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 测试完客户端二再解锁</span></span>
<span class="line"><span style="color:#A6ACCD;">unlock tables ;</span></span></code></pre></div><p>客户端二</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 能正常读</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> boys;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 虽然没报错，但是在阻塞状态</span></span>
<span class="line"><span style="color:#F78C6C;">update</span><span style="color:#A6ACCD;"> boys </span><span style="color:#F78C6C;">set</span><span style="color:#A6ACCD;"> boyName </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">王瑞</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011648642.png" alt="image-20230301164836413"></p><h4 id="表独占写锁" tabindex="-1">表独占写锁 <a class="header-anchor" href="#表独占写锁" aria-label="Permalink to &quot;表独占写锁&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221429228.png" alt="image-20220922142903107" style="zoom:80%;"><blockquote><p>左侧为客户端一，<strong>对指定表加了写锁</strong>，<strong>会阻塞右侧客户端的读和写</strong>。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011650233.png" alt="image-20230301165057007" style="zoom:80%;"><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">lock tables boys write ;</span></span>
<span class="line"><span style="color:#A6ACCD;">select * from boys;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 进行更新</span></span>
<span class="line"><span style="color:#A6ACCD;">-- [HY000][1099] Table &#39;boys&#39; was locked with a READ lock and can&#39;t be updated</span></span>
<span class="line"><span style="color:#A6ACCD;">update boys set boyName = &#39;王瑞&#39; where id=1;</span></span>
<span class="line"><span style="color:#A6ACCD;">unlock tables ;</span></span></code></pre></div><h3 id="元数据锁" tabindex="-1">元数据锁 <a class="header-anchor" href="#元数据锁" aria-label="Permalink to &quot;元数据锁&quot;">​</a></h3><blockquote><p>MDL加锁过程是系统自动控制，<code>无需显式使用</code>，<code>在访问一张表的时候会自动加上</code>。MDL锁主要<code>作用是维护表元数据的数据一致性</code>，在表 上有活动事务的时候，不可以对元数据进行写入操作。为了避免DML与DDL冲突，保证读写的正确性。开启事务之后才能查看到元数据锁</p></blockquote><blockquote><p>在MySQL5.5中引入了MDL，当对一张表进行增删改查的时候，自动加MDL读锁(共享)；当对表结构进行变更操作的时候，自动加MDL写锁(排他)。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221431804.png" alt="image-20220922143142676" style="zoom:80%;"><h4 id="元数据锁演示" tabindex="-1">元数据锁演示 <a class="header-anchor" href="#元数据锁演示" aria-label="Permalink to &quot;元数据锁演示&quot;">​</a></h4><h5 id="共享锁shared" tabindex="-1">共享锁SHARED <a class="header-anchor" href="#共享锁shared" aria-label="Permalink to &quot;共享锁SHARED&quot;">​</a></h5><blockquote><p>当执行SELECT、INSERT、UPDATE、DELETE等语句时，添加的是元数据共享锁（SHARED_READ /SHARED_WRITE）之间是兼容的。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221434802.png" alt="image-20220922143459587" style="zoom:80%;"><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">begin ;</span></span>
<span class="line"><span style="color:#A6ACCD;">select * from boys;</span></span></code></pre></div><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">begin ;</span></span>
<span class="line"><span style="color:#A6ACCD;">update boys set boyName = &#39;王瑞1&#39; where id=1;</span></span>
<span class="line"><span style="color:#A6ACCD;">commit ;</span></span></code></pre></div><h5 id="排他锁exclusive" tabindex="-1">排他锁exclusive <a class="header-anchor" href="#排他锁exclusive" aria-label="Permalink to &quot;排他锁exclusive&quot;">​</a></h5><blockquote><p>alter修改表结构就是排他锁，进入阻塞状态</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221435561.png" alt="image-20220922143537320" style="zoom:80%;"><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">begin ;</span></span>
<span class="line"><span style="color:#A6ACCD;">select * from boys;</span></span></code></pre></div><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 该事务会一直阻塞，直到上个事务commit才能执行成功</span></span>
<span class="line"><span style="color:#A6ACCD;">begin ;</span></span>
<span class="line"><span style="color:#A6ACCD;">alter table boys add column sex int ;</span></span></code></pre></div><h4 id="查看元数据锁" tabindex="-1">查看元数据锁 <a class="header-anchor" href="#查看元数据锁" aria-label="Permalink to &quot;查看元数据锁&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> object_type,object_schema,object_name,lock_type,lock_duration </span></span>
<span class="line"><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> performance_schema.metadata_locks;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221438856.png" alt="image-20220922143818707" style="zoom:80%;"><h3 id="意向锁" tabindex="-1">意向锁 <a class="header-anchor" href="#意向锁" aria-label="Permalink to &quot;意向锁&quot;">​</a></h3><h4 id="意向锁流程" tabindex="-1">意向锁流程 <a class="header-anchor" href="#意向锁流程" aria-label="Permalink to &quot;意向锁流程&quot;">​</a></h4><blockquote><p><strong>为了避免DML在执行时，加的行锁与表锁的冲突，在InnoDB中引入了意向锁，使得表锁不用检查每行数据是否加锁，使用意向锁来减少表锁的检查</strong>。</p></blockquote><p>首先客户端一，开启一个事务，然后执行DML操作，在执行DML语句时，会对涉及到的行加行锁。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221440335.png" alt="image-20220922144053203" style="zoom:80%;"><p>当客户端二，想对这张表加表锁时，会检查当前表是否有对应的行锁，如果没有，则添加表锁，此时就会从第一行数据，检查到最后一行数据，效率较低。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221441023.png" alt="image-20220922144108898" style="zoom:80%;"><p>有了意向锁之后 :客户端一，在执行DML操作时，会对涉及的行加行锁，同时也会对该表加上意向锁</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221441324.png" alt="image-20220922144131189" style="zoom:80%;"><p>而其他客户端，在对这张表加表锁的时候，会根据该表上所加的意向锁来判定是否可以成功加表锁，而不用逐行判断行锁情况了。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221441384.png" alt="image-20220922144144259" style="zoom:80%;"><h4 id="意向锁分类" tabindex="-1">意向锁分类 <a class="header-anchor" href="#意向锁分类" aria-label="Permalink to &quot;意向锁分类&quot;">​</a></h4><p>1.意向共享锁（IS）：由语句 select ... lock in share mode添加。</p><p>2.意向排他锁（IX）：由insert、update、delete、select ... for update 添加。</p><p>3.意向共享锁（IS）：与表锁共享锁（read）兼容，与表锁排它锁（write）互斥。</p><p>4.意向排他锁（IX）：与表锁共享锁（read）及排它锁（write）都互斥。意向锁之间不会互斥。</p><blockquote><p>一旦事务提交了，意向共享锁、意向排他锁，都会自动释放。</p></blockquote><h4 id="意向锁演示" tabindex="-1">意向锁演示 <a class="header-anchor" href="#意向锁演示" aria-label="Permalink to &quot;意向锁演示&quot;">​</a></h4><p>A. 意向共享锁与表读锁是兼容的</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221444260.png" alt="image-20220922144442007" style="zoom:80%;"><p>B. 意向排他锁与表读锁、写锁都是互斥的</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221445580.png" alt="image-20220922144504315" style="zoom:80%;"><h2 id="行级锁" tabindex="-1">行级锁 <a class="header-anchor" href="#行级锁" aria-label="Permalink to &quot;行级锁&quot;">​</a></h2><blockquote><p><strong>行级锁，每次操作锁住对应的行数据。锁定粒度最小，发生锁冲突的概率最低，并发度最高</strong>。**应用在InnoDB存储引擎中。**InnoDB的数据是基于索引组织的，行锁是通过对索引上的索引项加锁来实现的，而不是对记录加的锁。对于行级锁，主要分为以下三类：</p></blockquote><blockquote><p><strong>行锁（Record Lock）</strong>：<strong>锁定单个行记录的锁</strong>，<strong>防止其他事务对此行进行update和delete</strong>。在RC、RR隔离级别下都支持。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206181206191.png" alt="image-20220618120629117" style="zoom:67%;"><blockquote><p><strong>间隙锁（Gap Lock）</strong>：<strong>锁定索引记录间隙（不含该记录），确保索引记录间隙不变，防止其他事务在这个间隙进行insert，产生幻读</strong>。在RR隔离级别下都支持。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206181206853.png" alt="image-20220618120643788" style="zoom:67%;"><blockquote><p><strong>临键锁（Next-Key Lock）</strong>：行锁和间隙锁组合，同时锁住数据，并锁住数据前面的间隙Gap。在RR级别下支持</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206181206087.png" alt="image-20220618120658011" style="zoom:67%;"><p>MySQL中的行级锁主要包括：</p><blockquote><p>共享锁（Shared Lock）：也称为读锁，允许事务读取一行数据，但不能对数据进行修改，可以和其他事务的共享锁共存，但与排他锁互斥。</p></blockquote><blockquote><p>排他锁（Exclusive Lock）：也称为写锁，允许事务对数据进行修改和删除，但其他事务不能读取、修改和删除该数据，排他锁之间也是互斥的。</p></blockquote><blockquote><p>记录锁（Record Lock）：行级锁的一种，用于锁定一条记录，防止其他事务对该记录进行修改或删除，只对当前记录有效。</p></blockquote><blockquote><p>间隙锁（Gap Lock）：也称为间隙锁，锁定索引记录之间的空隙，防止其他事务在锁范围内插入新数据或修改已有数据，只对当前间隙有效。</p></blockquote><blockquote><p>临键锁（Next-Key Lock）：记录锁和间隙锁的组合，用于保证数据的一致性。对于有唯一索引的表，MySQL会自动加上临键锁，防止出现幻读现象。</p></blockquote><blockquote><p><strong>行级锁主要用于提高并发性和保证数据的一致性。当多个事务同时访问同一行数据时，通过行级锁可以避免产生冲突和数据异常</strong>。</p></blockquote><h3 id="行锁⭐" tabindex="-1">行锁⭐ <a class="header-anchor" href="#行锁⭐" aria-label="Permalink to &quot;行锁⭐&quot;">​</a></h3><h4 id="行锁入门" tabindex="-1">行锁入门 <a class="header-anchor" href="#行锁入门" aria-label="Permalink to &quot;行锁入门&quot;">​</a></h4><p>InnoDB实现了以下两种类型的行锁：</p><blockquote><p>1.共享锁（S）：<strong><code>允许一个事务去读一行，阻止其他事务获得相同数据集的排它锁</code></strong>。</p><p>2.排他锁（X）：<strong><code>允许获取排他锁的事务更新数据，阻止其他事务获得相同数据集的共享锁和排他锁</code></strong>。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220201213217166.png" alt="image-20220201213217166" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221454938.png" alt="image-20220922145436810" style="zoom:80%;"><h4 id="演示" tabindex="-1">演示 <a class="header-anchor" href="#演示" aria-label="Permalink to &quot;演示&quot;">​</a></h4><blockquote><p>默认情况下，InnoDB在 REPEATABLE READ事务隔离级别运行，InnoDB使用 next-key 锁进行搜索和索引扫描，以防止幻读。针对唯一索引进行检索时，对已存在的记录进行等值匹配时，将会自动优化为行锁。</p></blockquote><blockquote><p>InnoDB的行锁是针对于索引加的锁，不通过索引条件检索数据，那么InnoDB将对表中的所有记录加锁，此时就会升级为表锁。</p></blockquote><p>可以通过以下SQL，查看意向锁及行锁的加锁情况：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> object_schema,object_name,index_name,lock_type,lock_mode,lock_data </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> performance_schema.data_locks;</span></span></code></pre></div><p>演示行锁的时候，我们就通过上面这张表来演示一下。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">TABLE</span><span style="color:#A6ACCD;"> `</span><span style="color:#82AAFF;">stu</span><span style="color:#A6ACCD;">` ( </span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">NOT NULL</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">PRIMARY KEY</span><span style="color:#A6ACCD;"> AUTO_INCREMENT, </span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">255</span><span style="color:#A6ACCD;">) </span><span style="color:#C792EA;">DEFAULT</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">NULL</span><span style="color:#A6ACCD;">, </span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">age</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">NOT NULL</span><span style="color:#A6ACCD;"> </span></span>
<span class="line"><span style="color:#A6ACCD;">) ENGINE </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> InnoDB </span><span style="color:#F78C6C;">CHARACTER</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">SET</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> utf8mb4; </span></span>
<span class="line"><span style="color:#F78C6C;">INSERT INTO</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">stu</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">VALUES</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">tom</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">); </span></span>
<span class="line"><span style="color:#F78C6C;">INSERT INTO</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">stu</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">VALUES</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">3</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">cat</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">3</span><span style="color:#A6ACCD;">); </span></span>
<span class="line"><span style="color:#F78C6C;">INSERT INTO</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">stu</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">VALUES</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">8</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">rose</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">8</span><span style="color:#A6ACCD;">); </span></span>
<span class="line"><span style="color:#F78C6C;">INSERT INTO</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">stu</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">VALUES</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">11</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">jetty</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">11</span><span style="color:#A6ACCD;">); </span></span>
<span class="line"><span style="color:#F78C6C;">INSERT INTO</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">stu</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">VALUES</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">19</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">lily</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">19</span><span style="color:#A6ACCD;">); </span></span>
<span class="line"><span style="color:#F78C6C;">INSERT INTO</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">stu</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">VALUES</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">25</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">luci</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">25</span><span style="color:#A6ACCD;">);</span></span></code></pre></div><p>A. 普通的select语句，执行时，不会加锁。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221456537.png" alt="image-20220922145618319" style="zoom:80%;"><p>B. select...lock in share mode，加共享锁，共享锁与共享锁之间兼容。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221456296.png" alt="image-20220922145651884" style="zoom:80%;"><p>共享锁与排他锁之间互斥。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221457016.png" alt="image-20220922145723700" style="zoom:80%;"><p>客户端一获取的是id为1这行的共享锁，客户端二是可以获取id为3这行的排它锁的，因为不是同一行数据。 而如果客户端二想获取id为1这行的排他锁，会处于阻塞状态，以为共享锁与排他锁之间互斥。</p><p>C. 排它锁与排他锁之间互斥</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221458612.png" alt="image-20220922145809438" style="zoom:80%;"><p>D. 无索引行锁升级为表锁</p><p>stu表中数据如下:</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221458894.png" alt="image-20220922145845741" style="zoom:80%;"><p>我们在两个客户端中执行如下操作:</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221459516.png" alt="image-20220922145909280" style="zoom:80%;"><p>在客户端一中，开启事务，并执行update语句，更新name为Lily的数据，也就是id为19的记录 。然后在客户端二中更新id为3的记录，却不能直接执行，会处于阻塞状态，为什么呢？原因就是因为此时，客户端一，根据name字段进行更新时，name字段是没有索引的，如果没有索引，此时行锁会升级为表锁(因为行锁是对索引项加的锁，而name没有索引)。接下来，我们再针对name字段建立索引，索引建立之后，再次做一个测试：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221459697.png" alt="image-20220922145942410" style="zoom:80%;"><p>此时我们可以看到，客户端一，开启事务，然后依然是根据name进行更新。而客户端二，在更新id为3的数据时，更新成功，并未进入阻塞状态。 这样就说明，我们根据索引字段进行更新操作，就可以避免行锁升级为表锁的情况。</p><h3 id="间隙锁-临键锁" tabindex="-1">间隙锁/临键锁 <a class="header-anchor" href="#间隙锁-临键锁" aria-label="Permalink to &quot;间隙锁/临键锁&quot;">​</a></h3><h4 id="入门分析" tabindex="-1">入门分析 <a class="header-anchor" href="#入门分析" aria-label="Permalink to &quot;入门分析&quot;">​</a></h4><blockquote><p>默认情况下，InnoDB在 REPEATABLE READ事务隔离级别运行，InnoDB使用 next-key 锁进行搜索和索引扫描，以防止幻读。</p></blockquote><blockquote><p>1.<strong>索引上的等值查询(唯一索引)，给不存在的记录加锁时, 优化为间隙锁</strong> 。</p><p>2.<strong>索引上的等值查询(普通索引)，向右遍历时最后一个值不满足查询需求时，next-key lock 退化为间隙锁</strong>。</p><p>3.<strong>索引上的范围查询(唯一索引)--会访问到不满足条件的第一个值为止</strong>。</p></blockquote><blockquote><p>注意：<strong>间隙锁唯一目的是防止多个事务并发操作出现幻读现象。间隙锁可以共存，一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用间隙锁</strong>。</p></blockquote><blockquote><p>间隙锁是一种保护索引范围而不是索引记录的锁。当一个事务使用范围条件（例如 <code>WHERE col BETWEEN 1 AND 10</code>）或者非唯一索引条件（例如 <code>WHERE col = 1</code>）进行查询时，如果查询结果中的一个间隙（即不存在的索引记录之间的区域）可能被另一个事务插入新记录，那么MySQL会对该间隙进行间隙锁定，以防止其他事务插入新记录到该间隙中。间隙锁可以防止其他事务插入索引记录，但不会阻止其他事务插入间隙锁之间的记录。</p></blockquote><blockquote><p>临键锁是指锁定索引记录的锁。当一个事务使用唯一索引条件（例如 <code>WHERE col = 1</code>）进行查询时，如果查询结果中的一条索引记录被其他事务锁定了，那么MySQL会对该索引记录进行临键锁定，以防止其他事务修改或删除该记录。临键锁可以保护唯一索引记录，但不会阻止其他事务插入索引记录。</p></blockquote><blockquote><p>需要注意的是，间隙锁和临键锁只在使用事务引擎时才存在，例如InnoDB引擎。MyISAM引擎不支持行级锁，因此不会出现间隙锁和临键锁的情况。</p></blockquote><h4 id="示例演示" tabindex="-1">示例演示 <a class="header-anchor" href="#示例演示" aria-label="Permalink to &quot;示例演示&quot;">​</a></h4><p>A. 索引上的等值查询(唯一索引)，给不存在的记录加锁时, 优化为间隙锁 。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221501361.png" alt="image-20220922150104087" style="zoom:80%;"><p>B. 索引上的等值查询(非唯一普通索引)，向右遍历时最后一个值不满足查询需求时，next-keylock 退化为间隙锁。</p><p>介绍分析一下：</p><p>我们知道InnoDB的B+树索引，叶子节点是有序的双向链表。 假如，我们要根据这个二级索引查询值为18的数据，并加上共享锁，我们是只锁定18这一行就可以了吗？ 并不是，因为是非唯一索引，这个结构中可能有多个18的存在，所以，在加锁时会继续往后找，找到一个不满足条件的值（当前案例中也就是29）。此时会对18加临键锁，并对29之前的间隙加锁。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206181210437.png" alt="image-20220618121000365" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221501671.png" alt="image-20220922150140337" style="zoom:80%;"><p>C. 索引上的范围查询(唯一索引)--会访问到不满足条件的第一个值为止。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221502030.png" alt="image-20220922150206750" style="zoom:80%;"><p>查询的条件为id&gt;=19，并添加共享锁。 此时我们可以根据数据库表中现有的数据，将数据分为三个部分：</p><p>[19]、(19,25]、(25,+∞]，所以数据库数据在加锁是，就是将19加了行锁，25的临键锁（包含25及25之前的间隙），正无穷的临键锁(正无穷及之前的间隙)。</p><h2 id="锁面试题" tabindex="-1">锁面试题 <a class="header-anchor" href="#锁面试题" aria-label="Permalink to &quot;锁面试题&quot;">​</a></h2><h3 id="select-for-update" tabindex="-1">select ... for update <a class="header-anchor" href="#select-for-update" aria-label="Permalink to &quot;select ... for update&quot;">​</a></h3><blockquote><p>SELECT FOR UPDATE是 MySQL 中一种行级锁的语法，用于在事务中锁定被查询的行，以防止其他事务修改这些行。一般情况下，SELECT查询只是读取数据，而不对数据进行修改。但是，当多个事务同时修改同一行数据时，就可能会发生冲突，导致数据不一致。</p></blockquote><blockquote><p>因此，在某些情况下需要使用 <strong><code>SELECT FOR UPDATE</code></strong> 来锁定查询到的行，以保证数据的一致性。比如：用户扣减积分，用户的操作并不集中。但也要考虑系统自动赠送积分的并发情况，所以有必要加悲观锁限制一下，防止出现积分加错的情况发生。</p></blockquote><p>这时候就可以使用MYSQL中的<code>select ... for update</code>语法了。例如：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">begin</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">user</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> for </span><span style="color:#F78C6C;">update</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;"># 业务逻辑处理</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F78C6C;">update</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">user</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">set</span><span style="color:#A6ACCD;"> score</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">score</span><span style="color:#89DDFF;">-</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#F78C6C;">commit</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><blockquote><p>这样在一个事务中使用<code>for update</code>锁住一行记录，其他事务就不能在该事务提交之前，去更新那一行的数据。需要注意的是for update前的id条件，必须是表的<code>主键</code>或者<code>唯一索引</code>，不然行锁可能会失效，有可能变成<code>表锁</code>。</p></blockquote><blockquote><p><code>SELECT FOR UPDATE</code> 语句会在查询时对符合条件的行加锁，直到事务结束或者显式释放锁。这样，其他事务就无法修改这些行，从而避免了数据冲突。</p></blockquote><blockquote><p>需要注意的是，使用 <code>SELECT FOR UPDATE</code> 会导致性能下降，因为它会在查询时加锁，其他事务就无法访问这些行，直到锁被释放。因此，只有在必要的情况下才应该使用 <code>SELECT FOR UPDATE</code>。</p></blockquote><h1 id="mysql管理⭐⭐" tabindex="-1">MySQL管理⭐⭐ <a class="header-anchor" href="#mysql管理⭐⭐" aria-label="Permalink to &quot;MySQL管理⭐⭐&quot;">​</a></h1><h2 id="系统数据库" tabindex="-1">系统数据库 <a class="header-anchor" href="#系统数据库" aria-label="Permalink to &quot;系统数据库&quot;">​</a></h2><p>MySQL数据库安装完成后，会自带四个数据库</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220202113615510.png" alt="image-20220202113615510" style="zoom:80%;"><h2 id="常用工具" tabindex="-1">常用工具 <a class="header-anchor" href="#常用工具" aria-label="Permalink to &quot;常用工具&quot;">​</a></h2><h3 id="mysql客户端工具" tabindex="-1">mysql客户端工具 <a class="header-anchor" href="#mysql客户端工具" aria-label="Permalink to &quot;mysql客户端工具&quot;">​</a></h3><p>该mysql不是指mysql服务，而是指mysql的客户端工具。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206181045966.png" alt="image-20220618104508892" style="zoom:67%;"><blockquote><p><strong>-e选项可以在MySQL客户端执行SQL语句，而不用连接到MySQL数据库再执行</strong>。</p><p><strong>对于一些批处理脚本，这种方式尤其方便</strong></p></blockquote><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;"># 进入cmd中，books是数据库名,-e执行查询</span></span>
<span class="line"><span style="color:#A6ACCD;">mysql -uroot -p123456 books -e &quot;select * from account&quot;</span></span>
<span class="line"><span style="color:#A6ACCD;">mysql -uroot -p123456 -e &quot;show databases&quot;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220202115207122.png" alt="image-20220202115207122" style="zoom:80%;"><h3 id="mysqladmin管理工具" tabindex="-1">mysqladmin管理工具 <a class="header-anchor" href="#mysqladmin管理工具" aria-label="Permalink to &quot;mysqladmin管理工具&quot;">​</a></h3><p>mysqladmin 是一个执行管理操作的客户端程序。可以用它来检查服务器的配置和当前状态、创建并删除数据库等</p><blockquote><ol><li>启动和停止 MySQL 服务器</li><li>检查服务器状态</li><li>执行性能监控</li><li>管理数据库用户和权限</li><li>执行一些数据库维护任务，如备份、恢复等</li></ol></blockquote><div class="language-css"><button title="Copy Code" class="copy"></button><span class="lang">css</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">mysqladmin --help</span></span></code></pre></div><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 查看SQL版本，包含详细信息</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqladmin </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 </span><span style="color:#F78C6C;">version</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 检查 MySQL 服务器是否可用</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqladmin </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 ping</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 停止 MySQL 服务器</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqladmin </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 </span><span style="color:#F78C6C;">shutdown</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 显示 MySQL 服务器的状态信息</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqladmin </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 </span><span style="color:#F78C6C;">status</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 显示当前正在执行的查询列表</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqladmin </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 processlist</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 重新加载 MySQL 服务器配置文件</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqladmin </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 reload</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 创建数据库</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqladmin </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 </span><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> db2</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 删除数据库</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqladmin </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 </span><span style="color:#F78C6C;">drop</span><span style="color:#A6ACCD;"> db2</span></span></code></pre></div><h3 id="mysqlbinlog日志查看" tabindex="-1">mysqlbinlog日志查看 <a class="header-anchor" href="#mysqlbinlog日志查看" aria-label="Permalink to &quot;mysqlbinlog日志查看&quot;">​</a></h3><blockquote><p>由于服务器生成的二进制日志文件以二进制格式保存，所以如果想要检查这些文本的文本格式，就会使用到mysqlbinlog 日志管理工具。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206181049750.png" alt="image-20220618104943665" style="zoom:67%;"><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">cd </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">var</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">lib</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mysql</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqlbinlog mall</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">mysql</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">bin.000006</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqlbinlog </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">s mall</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">mysql</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">bin.000006</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211306035.png" alt="image-20220921130615788" style="zoom:80%;"><h3 id="mysqlshow信息查看" tabindex="-1">mysqlshow信息查看 <a class="header-anchor" href="#mysqlshow信息查看" aria-label="Permalink to &quot;mysqlshow信息查看&quot;">​</a></h3><blockquote><p>mysqlshow 客户端对象查找工具，用来很快地查找存在哪些数据库、数据库中的表、表中的列或者索引。</p></blockquote><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">mysqlshow -uroot -p123456 itcast-- 查询每个数据库的表的数量及表中记录的数量</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqlshow -uroot -p123456 --count</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">-- 查询books库中每个表中的字段数及行数</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqlshow -uroot -p123456 books --count</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">-- 查询books库中每个表中的字段书，及行数</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqlshow -uroot -p123456 books account --count</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">-- 查看表的详细信息</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqlshow -uroot -p123456 books country -i</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">-- 查看数据库的详细信息</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqlshow -uroot -p123456 books -i</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">-- 查看表字段的详细信息</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqlshow -uroot -p123456 books country name -i</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">-- 显示表信息时包括列信息</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqlshow -uroot -p123456 itcast user2 -v</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">-- 查看数据库表</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqlshow -uroot -p123456 itcast</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211547037.png" alt="image-20220921154703832" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220202120650595.png" alt="image-20220202120650595" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220202121111496.png" alt="image-20220202121111496" style="zoom:80%;"><h3 id="mysqldump数据和表导出⭐" tabindex="-1">mysqldump数据和表导出⭐ <a class="header-anchor" href="#mysqldump数据和表导出⭐" aria-label="Permalink to &quot;mysqldump数据和表导出⭐&quot;">​</a></h3><blockquote><p>mysqldump 客户端工具用来备份数据库或在不同数据库之间进行数据迁移。备份内容包含创建表，及插入表的SQL语句。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.6.11/202206181104398.png" alt="image-20220618110459285" style="zoom:67%;"><h4 id="备份全部数据库" tabindex="-1">备份全部数据库 <a class="header-anchor" href="#备份全部数据库" aria-label="Permalink to &quot;备份全部数据库&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 1.备份全部数据库的数据和结构</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqldump </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">A </span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">/</span><span style="color:#F78C6C;">data</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mysqlDump</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mydb.sql</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 2.备份全部数据库的结构（加 -d 参数,不包含数据）</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqldump </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">A </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">d </span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">/</span><span style="color:#F78C6C;">data</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mysqlDump</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mydb.sql</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqldump </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 </span><span style="color:#676E95;font-style:italic;">--all-databases  &gt; /data/mysqlDump/mydb.sql</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 3.备份全部数据库的数据(加 -t 参数)</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqldump </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">A </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">t </span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">/</span><span style="color:#F78C6C;">data</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mysqlDump</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mydb.sql</span></span></code></pre></div><h4 id="备份单个数据库" tabindex="-1">备份单个数据库 <a class="header-anchor" href="#备份单个数据库" aria-label="Permalink to &quot;备份单个数据库&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 4.备份单个数据库的数据和结构(数据库名mydb)</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqldump </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 mydb </span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">/</span><span style="color:#F78C6C;">data</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mysqlDump</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mydb.sql</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 5.备份单个数据库的结构</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqldump </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 mydb </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">d </span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">/</span><span style="color:#F78C6C;">data</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mysqlDump</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mydb.sql</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 6.备份单个数据库的数据</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqldump </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 mydb </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">t </span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">/</span><span style="color:#F78C6C;">data</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mysqlDump</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mydb.sql</span></span></code></pre></div><h4 id="备份多个数据库-表" tabindex="-1">备份多个数据库 &amp; 表 <a class="header-anchor" href="#备份多个数据库-表" aria-label="Permalink to &quot;备份多个数据库 &amp; 表&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 7.备份多个表的数据和结构（数据，结构的单独备份方法与上同）</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqldump </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 mydb t1 t2 </span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">/</span><span style="color:#F78C6C;">data</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mysqlDump</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mydb.sql</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 8.一次备份多个数据库</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqldump </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 </span><span style="color:#676E95;font-style:italic;">--databases db1 db2 &gt; /data/mysqlDump/mydb.sql</span></span></code></pre></div><h4 id="根据条件备份" tabindex="-1">根据条件备份 <a class="header-anchor" href="#根据条件备份" aria-label="Permalink to &quot;根据条件备份&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 9.根据条件导出数据</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqldump </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 </span><span style="color:#676E95;font-style:italic;">--databases db --tables a --where=&#39;id=1&#39; &gt;/tmp/a.sql</span></span></code></pre></div><h4 id="实战演练-2" tabindex="-1">实战演练 <a class="header-anchor" href="#实战演练-2" aria-label="Permalink to &quot;实战演练&quot;">​</a></h4><p>1、先查看MySQL信任目录</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">mysql </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456</span></span>
<span class="line"><span style="color:#A6ACCD;">show variables </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%secure_file_priv%</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211622160.png" alt="image-20220921162235013" style="zoom:80%;"><p>2、进行导出，会生成sql文件和txt文件</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 导出整个数据库</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqldump </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">T </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">var</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">lib</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mysql</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">files itcast</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 只备份单个表</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqldump </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">T </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">var</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">lib</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mysql</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">files itcast course</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211619648.png" alt="image-20220921161956514" style="zoom:80%;"><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 该数据用下面的mysqlimport导入</span></span>
<span class="line"><span style="color:#A6ACCD;">cat </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">var</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">lib</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mysql</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">files</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">course</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">txt</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.10.30/202209221734685.png" alt="image-20220922173438526" style="zoom:80%;"><h3 id="mysqlimport-source数据导入" tabindex="-1">mysqlimport/source数据导入 <a class="header-anchor" href="#mysqlimport-source数据导入" aria-label="Permalink to &quot;mysqlimport/source数据导入&quot;">​</a></h3><h4 id="mysqlimport" tabindex="-1">mysqlimport <a class="header-anchor" href="#mysqlimport" aria-label="Permalink to &quot;mysqlimport&quot;">​</a></h4><blockquote><p>mysqlimport 是客户端数据导入工具，<strong>用来导入mysqldump 加 -T 参数后导出的文本文件。</strong></p><p>注意：<strong>数据导入时文本文件要放在SQL信任目录</strong></p></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;"># 先查看MySQL信任目录</span></span>
<span class="line"><span style="color:#A6ACCD;">mysql </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456</span></span>
<span class="line"><span style="color:#A6ACCD;">show variables </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%secure_file_priv%</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211622160.png" alt="image-20220921162235013" style="zoom:80%;"><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">truncate table course</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">#</span><span style="color:#A6ACCD;"> 进行数据导入，其实就是导出时的数据格式</span></span>
<span class="line"><span style="color:#A6ACCD;">mysqlimport </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 itcast </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">var</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">lib</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mysql</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">files</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">course</span><span style="color:#89DDFF;">.</span><span style="color:#A6ACCD;">txt</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303010857982.png" alt="image-20230301085737872" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.10.30/202209221733462.png" alt="image-20220922173344312" style="zoom:80%;"><h4 id="source" tabindex="-1">source <a class="header-anchor" href="#source" aria-label="Permalink to &quot;source&quot;">​</a></h4><p>如果需要导入sql文件,可以使用mysql中的source 指令 :</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">source </span><span style="color:#89DDFF;">/</span><span style="color:#F78C6C;">root</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">xxxx.sql</span></span></code></pre></div><p>要进入cmd中mysql执行</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 进入mysql</span></span>
<span class="line"><span style="color:#A6ACCD;">mysql </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">database</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">s1</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 进入要导入的数据库</span></span>
<span class="line"><span style="color:#F78C6C;">use</span><span style="color:#A6ACCD;"> s1;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 导入sql脚本</span></span>
<span class="line"><span style="color:#A6ACCD;">source </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">var</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">lib</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mysql</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">files</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">xuexi.sql</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.10.30/202209221727680.png" alt="image-20220922172708481" style="zoom:80%;"><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 直接导入</span></span>
<span class="line"><span style="color:#A6ACCD;">mysql </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uroot </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p123456 </span><span style="color:#89DDFF;">&lt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">/</span><span style="color:#F78C6C;">data</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mysqlDump</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mydb.sql</span></span></code></pre></div><h1 id="innodb引擎" tabindex="-1">InnoDB引擎 <a class="header-anchor" href="#innodb引擎" aria-label="Permalink to &quot;InnoDB引擎&quot;">​</a></h1><p>进入正题前先简单看看MySQL的逻辑架构，相信我用的着。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022/202204251353506.png" alt="image-20220425135344388" style="zoom:67%;"><p>MySQL的逻辑架构大致可以分为三层：</p><ul><li>第一层：处理客户端连接、授权认证，安全校验等。</li><li>第二层：服务器<code>server</code>层，负责对SQL解释、分析、优化、执行操作引擎等。</li><li>第三层：存储引擎，负责MySQL中数据的存储和提取。</li></ul><blockquote><p>我们要知道MySQL的服务器层是不管理事务的，事务是由存储引擎实现的，而MySQL中支持事务的存储引擎又属<code>InnoDB</code>使用的最为广泛，所以后续文中提到的存储引擎都以<code>InnoDB</code>为主。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022/202204251354038.png" alt="image-20220425135424913" style="zoom:80%;"><p><strong>记住！</strong> <strong>记住！</strong> <strong>记住！</strong> 上边这张图，她是MySQL更新数据的基础流程，其中包括<code>redo log</code>、<code>bin log</code>、<code>undo log</code>三种日志间的大致关系，好了闲话少说直奔主题。</p><h2 id="逻辑存储结构" tabindex="-1">逻辑存储结构 <a class="header-anchor" href="#逻辑存储结构" aria-label="Permalink to &quot;逻辑存储结构&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220410143517913.png" alt="image-20220410143517913" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220410143553467.png" alt="image-20220410143553467" style="zoom:67%;"><h2 id="innodb架构" tabindex="-1">InnoDB架构 <a class="header-anchor" href="#innodb架构" aria-label="Permalink to &quot;InnoDB架构&quot;">​</a></h2><h3 id="整体架构图⭐" tabindex="-1">整体架构图⭐ <a class="header-anchor" href="#整体架构图⭐" aria-label="Permalink to &quot;整体架构图⭐&quot;">​</a></h3><blockquote><p>MySQL5.5 版本开始，默认使用InnoDB存储引擎，它擅长事务处理，具有崩溃恢复特性，在日常开发中使用非常广泛。下面是InnoDB架构图，<strong>左侧为内存结构，右侧为磁盘结构</strong>。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220410143653759.png" alt="image-20220410143653759" style="zoom:80%;"><h3 id="内存架构⭐" tabindex="-1">内存架构⭐ <a class="header-anchor" href="#内存架构⭐" aria-label="Permalink to &quot;内存架构⭐&quot;">​</a></h3><blockquote><p>在左侧的内存结构中，主要分为这么四大块儿： Buffer Pool、Change Buffer、Adaptive Hash Index、Log Buffer。 接下来介绍一下这四个部分。</p></blockquote><h4 id="buffer-pool" tabindex="-1">Buffer Pool <a class="header-anchor" href="#buffer-pool" aria-label="Permalink to &quot;Buffer Pool&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011742151.png" alt="image-20230301174207972" style="zoom:80%;"><blockquote><p>InnoDB存储引擎基于磁盘文件存储，访问物理硬盘和在内存中进行访问，速度相差很大，为了尽可能弥补这两者之间的I/O效率的差值，就需要把经常使用的数据加载到缓冲池中，避免每次访问都进行磁盘I/O。</p></blockquote><blockquote><p>在InnoDB的缓冲池中不仅缓存了索引页和数据页，还包含了undo页、插入缓存、自适应哈希索引以及InnoDB的锁信息等等。缓冲池 Buffer Pool，是主内存中的一个区域，里面可以缓存磁盘上经常操作的真实数据，在执行增</p></blockquote><blockquote><p>删改查操作时，先操作缓冲池中的数据（若缓冲池没有数据，则从磁盘加载并缓存），然后再以一定频率刷新到磁盘，从而减少磁盘IO，加快处理速度。缓冲池以Page页为单位，底层采用链表数据结构管理Page。根据状态，将Page分为三种类型：</p></blockquote><ul><li>free page：空闲page，未被使用。</li><li>clean page：被使用page，数据没有被修改过。</li><li>dirty page：脏页，被使用page，数据被修改过，也中数据与磁盘的数据产生了不一致。</li></ul><p>在专用服务器上，通常将多达80％的物理内存分配给缓冲池 。参数设置：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show variables </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">innodb_buffer_pool_size</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221514027.png" alt="image-20220922151408904" style="zoom:80%;"><h4 id="change-buffer" tabindex="-1">Change Buffer <a class="header-anchor" href="#change-buffer" aria-label="Permalink to &quot;Change Buffer&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011743405.png" alt="image-20230301174341240" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221518496.png" alt="image-20220922151823357" style="zoom:80%;"><blockquote><p>ChangeBuffer存在意义：<strong>与聚集索引不同，二级索引通常是非唯一的，并且以相对随机的顺序插入二级索引。同样，删除和更新可能会影响索引树中不相邻的二级索引页，如果每一次都操作磁盘，会造成大量的磁盘IO。有了ChangeBuffer之后，我们可以在缓冲池中进行合并处理，减少磁盘IO</strong>。</p></blockquote><h4 id="adaptive-hash-index" tabindex="-1">Adaptive Hash Index <a class="header-anchor" href="#adaptive-hash-index" aria-label="Permalink to &quot;Adaptive Hash Index&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011747687.png" alt="image-20230301174721525" style="zoom:80%;"><blockquote><p>InnoDB存储引擎会监控对表上各索引页的查询，如果观察到在特定的条件下hash索引可以提升速度，则建立hash索引，称之为自适应hash索引。<strong>自适应哈希索引，无需人工干预，是系统根据情况自动完成。</strong></p></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show variables </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%hash_index%</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221529210.png" alt="image-20220922152927089" style="zoom:80%;"><h4 id="log-buffer" tabindex="-1">Log Buffer <a class="header-anchor" href="#log-buffer" aria-label="Permalink to &quot;Log Buffer&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011943699.png" alt="image-20230301194345517" style="zoom:80%;"><p>innodb_log_buffer_size：缓冲区大小</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show variables </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%log_buffer%</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221538225.png" alt="image-20220922153819097" style="zoom:80%;"><p>innodb_flush_log_at_trx_commit：日志刷新到磁盘时机，取值主要包含以下三个：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show variables </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%flush_log%</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221538506.png" alt="image-20220922153859388" style="zoom:80%;"><p>1: 日志在每次事务提交时写入并刷新到磁盘，默认值。</p><p>0: 每秒将日志写入并刷新到磁盘一次。</p><p>2: 日志在每次事务提交后写入，并每秒刷新到磁盘一次。</p><h3 id="磁盘架构" tabindex="-1">磁盘架构 <a class="header-anchor" href="#磁盘架构" aria-label="Permalink to &quot;磁盘架构&quot;">​</a></h3><p>接下来，再来看看InnoDB体系结构的右边部分，也就是磁盘结构：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011946207.png" alt="image-20230301194606035" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011947025.png" alt="image-20230301194758841" style="zoom:80%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303011948010.png" alt="image-20230301194842832" style="zoom:80%;"><blockquote><p>文件目录：/var/lib/mysql/</p></blockquote><h4 id="system-tablespace" tabindex="-1">System Tablespace <a class="header-anchor" href="#system-tablespace" aria-label="Permalink to &quot;System Tablespace&quot;">​</a></h4><p>系统表空间是更改缓冲区的存储区域。如果表是在系统表空间而不是每个表文件或通用表空间中创建的，它也可能包含表和索引数据。(在MySQL5.x版本中还包含InnoDB数据字典、undolog等)</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show variables </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%innodb_data_file_path%</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221554145.png" alt="image-20220922155442003" style="zoom:80%;"><p>系统表空间，默认的文件名叫 ibdata1。</p><h4 id="file-per-table-tablespaces" tabindex="-1">File-Per-Table Tablespaces <a class="header-anchor" href="#file-per-table-tablespaces" aria-label="Permalink to &quot;File-Per-Table Tablespaces&quot;">​</a></h4><p>如果开启了innodb_file_per_table开关 ，则每个表的文件表空间包含单个InnoDB表的数据和索引 ，并存储在文件系统上的单个数据文件中。开关参数：innodb_file_per_table ，该参数默认开启。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show variables </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%innodb_file_per_table%</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221555598.png" alt="image-20220922155523463" style="zoom:80%;"><p>那也就是说，我们没创建一个表，都会产生一个表空间文件，如图：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221557815.png" alt="image-20220922155758650" style="zoom:80%;"><h4 id="general-tablespaces" tabindex="-1">General Tablespaces <a class="header-anchor" href="#general-tablespaces" aria-label="Permalink to &quot;General Tablespaces&quot;">​</a></h4><p>通用表空间，需要通过 CREATE TABLESPACE 语法创建通用表空间，在创建表时，可以指定该表空间。</p><p>A. 创建表空间</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">TABLESPACE</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">ts_name</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">ADD</span><span style="color:#A6ACCD;"> DATAFILE </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">file_name</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> ENGINE </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> engine_name;</span></span></code></pre></div><p>B. 创建表时指定表空间</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">TABLE</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">xxx</span><span style="color:#A6ACCD;"> ... TABLESPACE ts_name;</span></span></code></pre></div><h4 id="undo-tablespaces" tabindex="-1">Undo Tablespaces <a class="header-anchor" href="#undo-tablespaces" aria-label="Permalink to &quot;Undo Tablespaces&quot;">​</a></h4><p>撤销表空间，MySQL实例在初始化时会自动创建两个默认的undo表空间（初始大小16M），用于存储undo log日志。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221559315.png" alt="image-20220922155922154" style="zoom:80%;"><h4 id="temporary-tablespaces" tabindex="-1">Temporary Tablespaces <a class="header-anchor" href="#temporary-tablespaces" aria-label="Permalink to &quot;Temporary Tablespaces&quot;">​</a></h4><p>InnoDB 使用会话临时表空间和全局临时表空间。存储用户创建的临时表等数据。</p><h4 id="doublewrite-buffer-files" tabindex="-1">Doublewrite Buffer Files <a class="header-anchor" href="#doublewrite-buffer-files" aria-label="Permalink to &quot;Doublewrite Buffer Files&quot;">​</a></h4><p>双写缓冲区，innoDB引擎将数据页从Buffer Pool刷新到磁盘前，先将数据页写入双写缓冲区文件中，便于系统异常时恢复数据。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221600252.png" alt="image-20220922160028114" style="zoom:80%;"><h4 id="redo-log" tabindex="-1">Redo Log <a class="header-anchor" href="#redo-log" aria-label="Permalink to &quot;Redo Log&quot;">​</a></h4><blockquote><p>重做日志，是用来实现事务的持久性。该日志文件由两部分组成：重做日志缓冲（redo log buffer）以及重做日志文件（redo log）,前者是在内存中，后者在磁盘中。当事务提交之后会把所有修改信息都会存到该日志中, 用于在刷新脏页到磁盘时,发生错误时, 进行数据恢复使用。以循环方式写入重做日志文件，涉及两个文件：</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221601467.png" alt="image-20220922160106326" style="zoom:80%;"><h3 id="后台线程" tabindex="-1">后台线程 <a class="header-anchor" href="#后台线程" aria-label="Permalink to &quot;后台线程&quot;">​</a></h3><p>前面我们介绍了InnoDB的内存结构，以及磁盘结构，那么内存中我们所更新的数据，又是如何到磁盘中的呢？ 此时，就涉及到一组后台线程，接下来，就来介绍一些InnoDB中涉及到的后台线程</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221603516.png" alt="image-20220922160318364" style="zoom:50%;"><p>在InnoDB的后台线程中，分为4类，分别是：Master Thread 、IO Thread、Purge Thread、Page Cleaner Thread。</p><h4 id="master-thread" tabindex="-1">Master Thread <a class="header-anchor" href="#master-thread" aria-label="Permalink to &quot;Master Thread&quot;">​</a></h4><blockquote><p>核心后台线程，负责调度其他线程，还负责将缓冲池中的数据异步刷新到磁盘中, 保持数据的一致性，还包括脏页的刷新、合并插入缓存、undo页的回收 。</p></blockquote><h4 id="io-thread" tabindex="-1">IO Thread <a class="header-anchor" href="#io-thread" aria-label="Permalink to &quot;IO Thread&quot;">​</a></h4><blockquote><p>在InnoDB存储引擎中大量使用了AIO来处理IO请求, 这样可以极大地提高数据库的性能，而IO Thread主要负责这些IO请求的回调。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221606492.png" alt="image-20220922160645346" style="zoom:80%;"><p>我们可以通过以下的这条指令，查看到InnoDB的状态信息，其中就包含IO Thread信息。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show engine innodb </span><span style="color:#F78C6C;">status</span><span style="color:#A6ACCD;"> \G;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221605460.png" alt="image-20220922160541203" style="zoom:80%;"><h4 id="purge-thread" tabindex="-1">Purge Thread <a class="header-anchor" href="#purge-thread" aria-label="Permalink to &quot;Purge Thread&quot;">​</a></h4><blockquote><p>主要用于回收事务已经提交了的undo log，在事务提交之后，undo log可能不用了，就用它来回收。</p></blockquote><h4 id="page-cleaner-thread" tabindex="-1">Page Cleaner Thread <a class="header-anchor" href="#page-cleaner-thread" aria-label="Permalink to &quot;Page Cleaner Thread&quot;">​</a></h4><blockquote><p>协助 Master Thread 刷新脏页到磁盘的线程，它可以减轻 Master Thread 的工作压力，减少阻塞。</p></blockquote><h2 id="事务原理" tabindex="-1">事务原理 <a class="header-anchor" href="#事务原理" aria-label="Permalink to &quot;事务原理&quot;">​</a></h2><blockquote><p>事务是一组操作的集合，它是一个不可分割的工作单位，事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求，即这些操作 <strong>要么同时成功，要么同时失败</strong>。</p></blockquote><h3 id="事务特性" tabindex="-1">事务特性 <a class="header-anchor" href="#事务特性" aria-label="Permalink to &quot;事务特性&quot;">​</a></h3><blockquote><ul><li>原子性（Atomicity）：<strong>事务是不可分割的最小操作单元，要么全部成功，要么全部失败。</strong></li><li>一致性（Consistency）：<strong>事务完成时，必须使所有的数据都保持一致状态</strong>。</li><li>隔离性（Isolation）：<strong>数据库系统提供的隔离机制，保证事务在不受外部并发操作影响的独立环境下运行</strong>。</li><li>持久性（Durability）：<strong>事务一旦提交或回滚，它对数据库中的数据的改变就是永久的</strong>。</li></ul></blockquote><h3 id="innodb引擎如何保证事务特性⭐" tabindex="-1">InnoDB引擎如何保证事务特性⭐ <a class="header-anchor" href="#innodb引擎如何保证事务特性⭐" aria-label="Permalink to &quot;InnoDB引擎如何保证事务特性⭐&quot;">​</a></h3><p>那实际上，我们研究事务的原理，就是研究MySQL的InnoDB引擎是如何保证事务的这四大特性的</p><blockquote><p>而对于这四大特性，实际上分为两个部分。 其中的原子性、一致性、持久化，实际上是由InnoDB中的两份日志来保证的，一份是redo log日志，一份是undo log日志。 而持久性是通过数据库的锁，加上MVCC来保证的。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221624227.png" alt="image-20220204194010823" style="zoom:67%;"><blockquote><p>我们在讲解事务原理的时候，主要就是来研究一下redolog，undolog以及MVCC。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303012042541.png" alt="image-20230301204240403" style="zoom:80%;"><h3 id="redo-log-持久性" tabindex="-1">redo log(持久性) <a class="header-anchor" href="#redo-log-持久性" aria-label="Permalink to &quot;redo log(持久性)&quot;">​</a></h3><blockquote><p>重做日志，记录的是事务提交时数据页的物理修改，是用来实现事务的持久性。MySQL 中的 Redo Log 是一种用于提高事务处理能力和数据恢复性的机制。它是 MySQL 中的一种日志，用于记录已经提交的事务对于数据库所做的修改。Redo Log 的主要作用是在系统崩溃等异常情况下，用于恢复数据。</p></blockquote><blockquote><p>具体来说，当一个事务提交时，MySQL 将事务所做的修改记录到 Redo Log 中，并将这些操作写入到磁盘的 Redo Log 文件中。这个过程称为“写日志（write-ahead logging）”。MySQL 系统在执行一项更新操作时，首先将更新操作写入 Redo Log 中，然后再将操作更新到磁盘上的数据文件中。这样，在系统崩溃等异常情况下，MySQL 可以利用 Redo Log 文件中记录的操作来恢复数据。</p></blockquote><blockquote><p>在 MySQL 中，Redo Log 是以固定大小的“日志块（log block）”的形式存在。每个日志块的大小为 512 字节，每个日志块都会被编号，并且 Redo Log 中的日志块是循环写入的。当 Redo Log 文件写满后，MySQL 会将最旧的日志块覆盖掉，从而保证 Redo Log 文件始终不会占满磁盘空间。</p></blockquote><blockquote><p>需要注意的是，Redo Log 只记录已经提交的事务的操作，也就是说，如果一个事务没有提交，那么其操作就不会被记录到 Redo Log 中。因此，当系统崩溃后，MySQL 可能需要使用“回滚日志（rollback log）”来回滚未提交的事务。</p></blockquote><blockquote><p>该日志文件由两部分组成：重做日志缓冲（redo log buffer）以及重做日志文件（redo log file）,前者是在内存中，后者在磁盘中。当事务提交之后会把所有修改信息都存到该日志文件中, 用于在刷新脏页到磁盘,发生错误时, 进行数据恢复使用。如果没有redolog，可能会存在什么问题的？ 我们一起来分析一下。</p></blockquote><blockquote><p>我们知道，在InnoDB引擎中的内存结构中，主要的内存区域就是缓冲池，在缓冲池中缓存了很多的数据页。 当我们在一个事务中，执行多个增删改的操作时，InnoDB引擎会先操作缓冲池中的数据，如果缓冲区没有对应的数据，会通过后台线程将磁盘中的数据加载出来，存放在缓冲区中，然后将缓冲池中的数据修改，修改后的数据页我们称为脏页。 而脏页则会在一定的时机，通过后台线程刷新到磁盘中，从而保证缓冲区与磁盘的数据一致。</p></blockquote><blockquote><p>而缓冲区的脏页数据并不是实时刷新的，而是一段时间之后将缓冲区的数据刷新到磁盘中，假如刷新到磁盘的过程出错了，而提示给用户事务提交成功，而数据却没有持久化下来，这就出现问题了，没有保证事务的持久性。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221611686.png" alt="image-20220922161119530" style="zoom:67%;"><blockquote><p>那么，如何解决上述的问题呢？ 在InnoDB中提供了一份日志 redo log，接下来我们再来分析一下，通过redolog如何解决这个问题。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221611643.png" alt="image-20220922161156471" style="zoom:67%;"><blockquote><p>有了redolog之后，当对缓冲区的数据进行增删改之后，会首先将操作的数据页的变化，记录在redo log buffer中。在事务提交时，会将redo log buffer中的数据刷新到redo log磁盘文件中。过一段时间之后，如果刷新缓冲区的脏页到磁盘时，发生错误，此时就可以借助于redo log进行数据恢复，这样就保证了事务的持久性。</p></blockquote><blockquote><p>而如果脏页成功刷新到磁盘 或 或者涉及到的数据已经落盘，此时redolog就没有作用了，就可以删除了，所以存在的两个redolog文件是循环写的。那为什么每一次提交事务，要刷新redo log 到磁盘中呢，而不是直接将buffer pool中的脏页刷新到磁盘呢 ?</p></blockquote><blockquote><p>因为在业务操作中，我们操作数据一般都是随机读写磁盘的，而不是顺序读写磁盘。 而redo log在往磁盘文件中写入数据，由于是日志文件，所以都是顺序写的。顺序写的效率，要远大于随机写。 这种先写日志的方式，称之为 WAL即Write-Ahead Logging。</p></blockquote><h3 id="undo-log-原子性" tabindex="-1">undo log(原子性) <a class="header-anchor" href="#undo-log-原子性" aria-label="Permalink to &quot;undo log(原子性)&quot;">​</a></h3><blockquote><p>回滚日志，<strong>用于记录数据被修改前的信息</strong> , 作用包含两个 : <strong>提供回滚 和 MVCC(多版本并发控制)</strong> 。在 MySQL 中，Undo Log（撤销日志）用于实现事务的原子性和一致性，确保在发生错误或回滚事务时，MySQL 数据库可以恢复到正确的状态。</p></blockquote><blockquote><p>具体来说，当一个事务开始时，MySQL 就会为该事务分配一段用于保存 undo log 的空间。在事务执行期间，所有对数据的修改都会先记录到 undo log 中，这些记录称为“撤销记录”或“回滚操作”。每个撤销记录都包含了修改前的值，以便在回滚事务时恢复原始值。</p></blockquote><blockquote><p>当事务提交时，MySQL 会将 undo log 中的所有记录清空，因为这些操作已经被永久保存在磁盘上了。如果事务回滚，那么 MySQL 就会根据 undo log 中的记录来撤销该事务所做的修改，使得数据恢复到事务开始之前的状态。</p></blockquote><blockquote><p>需要注意的是，Undo Log 和 Redo Log（重做日志）不同。Redo Log 用于实现事务的持久性，即确保在系统崩溃时不会丢失已提交的事务。而 Undo Log 则是用于实现事务的原子性和一致性，即确保在回滚事务时数据能够恢复到正确的状态。</p></blockquote><p>UndoLog 一般是逻辑日志，主要分为两种：</p><p>insert undo log</p><blockquote><p>代表事务在insert新记录时产生的undo log, 只在事务回滚时需要，并且在事务提交后可以被立即丢弃</p></blockquote><p>update undo log</p><blockquote><p>事务在进行update或delete时产生的undo log; 不仅在事务回滚时需要，在快照读时也需要；所以不能随便删除，只有在快速读或事务回滚不涉及该日志时，对应的日志才会被purge线程统一清除</p></blockquote><p><code>undo log</code>属于逻辑日志，如其名主要起到回滚的作用，它是保证事务原子性的关键。记录的是数据修改前的状态，在数据修改的流程中，同时会记录一条与当前操作相反的逻辑日志到<code>undo log</code>中。</p><p>我们举个栗子：假如更新ID=1记录的name字段，name原始数据为小富，现改name为程序员内点事</p><p>事务执行<code>update X set name = 程序员内点事 where id =1</code>语句时，先会在<code>undo log</code>中记录一条相反逻辑的<code>update X set name = 小富 where id =1</code>记录，这样当某些原因导致服务异常事务失败，就可以借助<code>undo log</code>将数据回滚到事务执行前的状态，保证事务的完整性。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022/202204251359294.png" alt="image-20220425135936150" style="zoom:67%;"><p>那可能有人会问：同一个事物内的一条记录被多次修改，那是不是每次都要把数据修改前的状态都写入<code>undo log</code>呢？</p><p>答案是不会的！</p><p><code>undo log</code>只负责记录事务开始前要修改数据的原始版本，当我们再次对这行数据进行修改，所产生的修改记录会写入到<code>redo log</code>，<code>undo log</code>负责完成回滚，<code>redo log</code>负责完成前滚。</p><h3 id="回滚" tabindex="-1">回滚 <a class="header-anchor" href="#回滚" aria-label="Permalink to &quot;回滚&quot;">​</a></h3><p>未提交的事务，即事务未执行<code>commit</code>。但该事务内修改的脏页中，可能有一部分脏块已经刷盘。如果此时数据库实例宕机重启，就需要用回滚来将先前那部分已经刷盘的脏块从磁盘上撤销。</p><h3 id="前滚" tabindex="-1">前滚 <a class="header-anchor" href="#前滚" aria-label="Permalink to &quot;前滚&quot;">​</a></h3><p>未完全提交的事务，即事务已经执行<code>commit</code>，但该事务内修改的脏页中只有一部分数据被刷盘，另外一部分还在<code>buffer pool</code>缓存上，如果此时数据库实例宕机重启，就需要用前滚来完成未完全提交的事务。将先前那部分由于宕机在内存上的未来得及刷盘数据，从<code>redo log</code>中恢复出来并刷入磁盘。</p><blockquote><p>数据库实例恢复时，先做前滚，后做回滚。</p></blockquote><p>如果你仔细看过了上边的 <code>MySQL数据更新流程图</code> 就会发现，<code>undo log</code>、<code>redo log</code>、<code>bin log</code>三种日志都是在刷脏页之前就已经刷到磁盘了的，相互协作最大限度保证了用户提交的数据不丢失。</p><h2 id="mvcc-多版本并发控制" tabindex="-1">MVCC(多版本并发控制) <a class="header-anchor" href="#mvcc-多版本并发控制" aria-label="Permalink to &quot;MVCC(多版本并发控制)&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303012037701.png" alt="image-20230301203705547" style="zoom:80%;"><h3 id="基本概念" tabindex="-1">基本概念 <a class="header-anchor" href="#基本概念" aria-label="Permalink to &quot;基本概念&quot;">​</a></h3><h4 id="当前读" tabindex="-1">当前读 <a class="header-anchor" href="#当前读" aria-label="Permalink to &quot;当前读&quot;">​</a></h4><blockquote><p><strong>读取的是记录的最新版本，读取时还要保证其他并发事务不能修改当前记录，会对读取的记录进行加锁</strong>。对于我们日常的操作，如：select ... lock in share mode(共享锁)，select ...for update、update、insert、delete(排他锁)都是当前读。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221620371.png" alt="image-20220922162027146"><blockquote><p><strong>在测试中我们可以看到，即使是在默认的RR隔离级别下，事务A中依然可以读取到事务B最新提交的内容，因为在查询语句后面加上了 lock in share mode 共享锁，此时是当前读操作</strong>。当然，当我们加排他锁的时候，也是当前读操作。</p></blockquote><h4 id="快照读" tabindex="-1">快照读 <a class="header-anchor" href="#快照读" aria-label="Permalink to &quot;快照读&quot;">​</a></h4><blockquote><p><strong>简单的select（不加锁）就是快照读，快照读，读取的是记录数据的可见版本，有可能是历史数据，不加锁，是非阻塞读</strong>。</p></blockquote><ul><li>Read Committed：每次select，都生成一个快照读。</li><li>Repeatable Read：开启事务后第一个select语句才是快照读的地方。</li><li>Serializable：快照读会退化为当前读。</li></ul><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221621407.png" alt="image-20220922162146147" style="zoom:80%;"><blockquote><p>在测试中,我们看到即使事务B提交了数据,事务A中也查询不到。 原因就是因为普通的select是快照读，而在当前默认</p><p>的RR隔离级别下，开启事务后第一个select语句才是快照读的地方，后面执行相同的select语句都是从快照中获取数</p><p>据，可能不是当前的最新数据，这样也就保证了可重复读。</p></blockquote><h4 id="mvcc" tabindex="-1">MVCC <a class="header-anchor" href="#mvcc" aria-label="Permalink to &quot;MVCC&quot;">​</a></h4><blockquote><p>全称 Multi-Version Concurrency Control，多版本并发控制。指维护一个数据的多个版本，使得读写操作没有冲突，快照读为MySQL实现MVCC提供了一个非阻塞读功能。MVCC的具体实现，还需要依赖于数据库记录中的三个隐式字段、undo log日志、readView。接下来，我们再来介绍一下InnoDB引擎的表中涉及到的隐藏字段 、undolog 以及 readview，从而来介绍一下MVCC的原理。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221624231.png" alt="image-20220204193643740" style="zoom:80%;"><p>在这里我先为大家理清楚一个概念：我们常说的MVCC是由MySQL数据库InnoDB存储引擎实现的，并非是由MySQL本身实现的，不同的存储引擎，对MVCC都有不同的实现标准。</p><p>所以当你在面试官面前说：”MySQL使用了MVCC实现了xxxxxx“，面试官一下子就把你给逮住了，说明你连MySQL和InnoDB之间的关系都模糊不清😑。</p><blockquote><p>那么，当你听到了“多版本”、“并发访问”这两个词，你也许就知道了，InnoDB使用MVCC来解决并发问题的方法，就是让每个不同的事务访问查询同一行数据时，每个事务修改的都是这行数据的不同版本，InnoDB只需要去记录这个数据的访问链，就可以实现一个SELECT操作的并发执行。</p></blockquote><p>那么，它具体是如何实现的呢？</p><p>MVCC利用了多版本的思想，在 MVCC 中事务的所有写操作（INSERT、UPDATE、DELETE）会为数据行新增一个最新的版本快照，而读操作是去读旧版本的快照，也就是说，读操作和写操作是分离的，二者之间没有依赖、互斥关系。</p><h3 id="mvcc实现原理-隐藏字段" tabindex="-1">MVCC实现原理---隐藏字段 <a class="header-anchor" href="#mvcc实现原理-隐藏字段" aria-label="Permalink to &quot;MVCC实现原理---隐藏字段&quot;">​</a></h3><h4 id="隐藏字段" tabindex="-1">隐藏字段 <a class="header-anchor" href="#隐藏字段" aria-label="Permalink to &quot;隐藏字段&quot;">​</a></h4><blockquote><p>当我们创建了下面的这张表，我们在查看表结构的时候，就可以显式的看到这三个字段。 实际上除了这三个字段以外，InnoDB还会自动的给我们添加三个隐藏字段及其含义分别是：</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221624232.png" alt="image-20220204193117878" style="zoom:80%;"><blockquote><p>而上述的前两个字段是肯定会添加的， 是否添加最后一个字段DB_ROW_ID，得看当前表有没有主键，如果有主键，则不会添加该隐藏字段。</p></blockquote><h4 id="测试" tabindex="-1">测试 <a class="header-anchor" href="#测试" aria-label="Permalink to &quot;测试&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 进入itcast数据库</span></span>
<span class="line"><span style="color:#A6ACCD;">cd </span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">var</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">lib</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mysql</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">itcast</span></span>
<span class="line"><span style="color:#A6ACCD;">ibd2sdi user.ibd</span></span></code></pre></div><blockquote><p>查看到的表结构信息中，有一栏 columns，在其中我们会看到处理我们建表时指定的字段以外，还有额外的两个字段 分别是：DB_TRX_ID 、 DB_ROLL_PTR ，因为该表有主键，所以没有DB_ROW_ID隐藏字段。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221636800.png" alt="image-20220922163603654" style="zoom:80%;"><h3 id="mvcc实现原理-undolog版本链" tabindex="-1">MVCC实现原理---undolog版本链 <a class="header-anchor" href="#mvcc实现原理-undolog版本链" aria-label="Permalink to &quot;MVCC实现原理---undolog版本链&quot;">​</a></h3><h4 id="介绍" tabindex="-1">介绍 <a class="header-anchor" href="#介绍" aria-label="Permalink to &quot;介绍&quot;">​</a></h4><blockquote><p>回滚日志，在insert、update、delete的时候产生的便于数据回滚的日志。当insert的时候，产生的undo log日志只在回滚时需要，在事务提交后，可被立即删除。 而update、delete的时候，产生的undo log日志不仅在回滚时需要，在快照读时也需要，不会立即被删除。</p></blockquote><h4 id="版本链" tabindex="-1">版本链 <a class="header-anchor" href="#版本链" aria-label="Permalink to &quot;版本链&quot;">​</a></h4><p>有一张表原始数据为：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221639684.png" alt="image-20220922163946545" style="zoom:67%;"><blockquote><p>DB_TRX_ID : 代表最近修改事务ID，记录插入这条记录或最后一次修改该记录的事务ID，是自增的。</p><p>DB_ROLL_PTR ： 由于这条数据是才插入的，没有被更新过，所以该字段值为null。</p></blockquote><p>然后，有四个并发事务同时在访问这张表。</p><p>A. 第一步</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221640176.png" alt="image-20220922164029010" style="zoom:80%;"><p>当事务2执行第一条修改语句时，会记录undo log日志，记录数据变更之前的样子; 然后更新记录，</p><p>并且记录本次操作的事务ID，回滚指针，回滚指针用来指定如果发生回滚，回滚到哪一个版本。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221640263.png" alt="image-20220922164056126" style="zoom:80%;"><p>B.第二步</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221641577.png" alt="image-20220922164113424" style="zoom:80%;"><p>当事务3执行第一条修改语句时，也会记录undo log日志，记录数据变更之前的样子; 然后更新记</p><p>录，并且记录本次操作的事务ID，回滚指针，回滚指针用来指定如果发生回滚，回滚到哪一个版本。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221641237.png" alt="image-20220922164142084" style="zoom:80%;"><p>C. 第三步</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221642726.png" alt="image-20220922164205562" style="zoom:80%;"><p>当事务4执行第一条修改语句时，也会记录undo log日志，记录数据变更之前的样子; 然后更新记</p><p>录，并且记录本次操作的事务ID，回滚指针，回滚指针用来指定如果发生回滚，回滚到哪一个版本。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221642667.png" alt="image-20220922164231514" style="zoom:80%;"><blockquote><p>最终我们发现，不同事务或相同事务对同一条记录进行修改，会导致该记录的undolog生成一条记录版本链表，链</p><p>表的头部是最新的旧记录，链表尾部是最早的旧记录。</p></blockquote><h3 id="mvcc实现原理-read-view读视图" tabindex="-1">MVCC实现原理---Read View读视图 <a class="header-anchor" href="#mvcc实现原理-read-view读视图" aria-label="Permalink to &quot;MVCC实现原理---Read View读视图&quot;">​</a></h3><h4 id="四个核心字段" tabindex="-1">四个核心字段 <a class="header-anchor" href="#四个核心字段" aria-label="Permalink to &quot;四个核心字段&quot;">​</a></h4><blockquote><p>ReadView（读视图）是 快照读 SQL执行时MVCC提取数据的依据，记录并维护系统当前活跃的事务（未提交的）id。ReadView中包含了四个核心字段：</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221624228.png" alt="image-20220204193424753" style="zoom:80%;"><h4 id="版本链数据访问规则" tabindex="-1">版本链数据访问规则 <a class="header-anchor" href="#版本链数据访问规则" aria-label="Permalink to &quot;版本链数据访问规则&quot;">​</a></h4><p>而在readview中就规定了版本链数据的访问规则：trx_id 代表当前undolog版本链对应事务ID。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221624229.png" alt="image-20220204193541222" style="zoom:80%;"><p>不同的隔离级别，生成ReadView的时机不同：</p><blockquote><ul><li>READ COMMITTED ：<strong>在事务中每一次执行快照读时生成ReadView</strong>。</li><li>REPEATABLE READ：<strong>仅在事务中第一次执行快照读时生成ReadView，后续复用该ReadView</strong>。</li></ul></blockquote><h3 id="原理分析" tabindex="-1">原理分析 <a class="header-anchor" href="#原理分析" aria-label="Permalink to &quot;原理分析&quot;">​</a></h3><h4 id="rc隔离级别" tabindex="-1">RC隔离级别 <a class="header-anchor" href="#rc隔离级别" aria-label="Permalink to &quot;RC隔离级别&quot;">​</a></h4><p>RC隔离级别下，在事务中每一次执行快照读时生成ReadView。</p><p>我们就来分析事务5中，两次快照读读取数据，是如何获取数据的?</p><p>在事务5中，查询了两次id为30的记录，由于隔离级别为Read Committed，所以每一次进行快照读</p><p>都会生成一个ReadView，那么两次生成的ReadView如下。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221624230.png" alt="image-20220204193822058" style="zoom:80%;"><p>那么这两次快照读在获取数据时，就需要根据所生成的ReadView以及ReadView的版本链访问规则，</p><p>到undolog版本链中匹配数据，最终决定此次快照读返回的数据。</p><p>A. 先来看第一次快照读具体的读取过程：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221703452.png" alt="image-20220922170337303" style="zoom:80%;"><p>B. 再来看第二次快照读具体的读取过程:</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221704711.png" alt="image-20220922170409547" style="zoom:80%;"><h4 id="rr隔离级别" tabindex="-1">RR隔离级别 <a class="header-anchor" href="#rr隔离级别" aria-label="Permalink to &quot;RR隔离级别&quot;">​</a></h4><blockquote><p>RR隔离级别下，仅在事务中第一次执行快照读时生成ReadView，后续复用该ReadView。 而RR 是可重复读，在一个事务中，执行两次相同的select语句，查询到的结果是一样的。那MySQL是如何做到可重复读的呢? 我们简单分析一下就知道了</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221651845.png" alt="image-20220922165141705" style="zoom:80%;"><p>我们看到，在RR隔离级别下，只是在事务中第一次快照读时生成ReadView，后续都是复用该ReadView，那么既然</p><p>ReadView都一样， ReadView的版本链匹配规则也一样， 那么最终快照读返回的结果也是一样的。</p><p>所以呢，MVCC的实现原理就是通过 InnoDB表的隐藏字段、UndoLog 版本链、ReadView来实现的。</p><p>而MVCC + 锁，则实现了事务的隔离性。 而一致性则是由redolog 与 undolog保证。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209221624231.png" alt="image-20220204193731933" style="zoom:80%;"><h3 id="mvcc如何实现可重复读" tabindex="-1">MVCC如何实现可重复读？ <a class="header-anchor" href="#mvcc如何实现可重复读" aria-label="Permalink to &quot;MVCC如何实现可重复读？&quot;">​</a></h3><p>ok，假设现在事务A和事务B同时对主键id = 1进行操作。事务A的id为20，事务B的id为30。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208111548949.png" alt="image-20220811154809792" style="zoom:67%;"><p>那么这两个事务就会创建各自的Read View：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208111548957.png" alt="image-20220811154819870" style="zoom:67%;"><p>此时事务A的creator_trx_id=20，事务B的creator_trx_id=30。</p><p>由于仅有两个活跃的事务，事务id分别为20和30。事务列表中最小的的事务id是事务A，所以min_trx_id应该为20，下一个也就是最大的事务id的max_trx_id值应该为事务B的下一个id，也就是31。</p><p>事务A去读取主键id为1的数据，找到了记录后就会去查看该记录的trx_id，事务A查看到该记录的trx_id值为10。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208111548350.png" alt="image-20220811154835262" style="zoom:80%;"><p>随后和自己的creator_trx_id值进行比较： <img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208111548068.png" alt="image-20220811154846974" style="zoom:80%;"></p><p>发现主键id=1这条记录.trx_id = 10 &lt; 自己.creator_trx_id = 20，就判断到该记录的事务id不存在于活跃的事务列表中并且小于自己的事务id，这代表本次记录S的值是在自己查询之前提交的，那就可以放心的读取啦。</p><p>读取完之后，会将该记录的trx_id修改为自己的事务id。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208111549454.png" alt="image-20220811154900367" style="zoom:67%;"><p>然后，把fancy的age从28又改成了30🙃。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208111549723.png" alt="image-20220811154914629" style="zoom:67%;"><p>那么还有什么字段此时也会被修改吗？没错，就是我们刚刚提到的，Undo Log的另一个隐藏字段：roll_pointer指针。它会去指向被事务A修改之前的版本，也就是fancy的年龄还是28时候的地址，就为了用来记录，方便下次被查询： <img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208111549942.png" alt="image-20220811154924805" style="zoom:67%;"></p><p>随后，事务B也进来了，哈哈。</p><p>它也要进行对主键id为1的update操作。把fancy的年龄直接从30更改为50！</p><p>此时会再次进行一次trx_id的比较过程，去判断自己的creator_trx_id是否大于这条记录对应的trx_id，如果大于，就去修改这条记录的值，将年龄从30修改为50：</p><p><img src="https://mmbiz.qpic.cn/mmbiz_jpg/LUuerhGpzYOZI37ypufNRfc3eIcoViaRshIsVazrTzpbEdPpUwTYzwLkDsY8lMHiaIsOf9KTzs2lbuKD4JqiaozIg/640?wx_fmt=jpeg&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p><img src="https://mmbiz.qpic.cn/mmbiz_jpg/LUuerhGpzYOZI37ypufNRfc3eIcoViaRsyIWOC9icpxPDr3YYXlLPuYZEjvdNBUX4sQ0ofWzkusbDadmicgVQiaPaQ/640?wx_fmt=jpeg&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>重点来了！</p><p>过了一会，如果事务A再次去读取主键id=1这行的值，发现这条记录的trx_id已经变成了30，就会再次进行值的区间比较：发现自己.trx_id(20)&lt;主键id=1这条记录.trx_id(30)&lt;max_trx_id(31)，并且trx_id为30的值存在于m_ids中，就代表自己读取到的是和自己同一时间范围内一块启动的另一个未提交的活跃事务所修改的值。</p><p><img src="https://mmbiz.qpic.cn/mmbiz_jpg/LUuerhGpzYOZI37ypufNRfc3eIcoViaRs3zmgIgbB3jyHJUq4ibpB2lQSpkTZ8IrtHXIR5icKH07qhqbcgPRwNBSw/640?wx_fmt=jpeg&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>那么此时事务A是不会去读取这条记录对应的数据的，它会通过Undo Log上的roll_pointer指向的地址去查找上一个旧版本的记录，直到找到第一条trx_id小于等于自己的事务id并且不存在于m_ids列表中的记录，代表是别的事务已经提交的最后一条记录，然后读取它。 <img src="https://mmbiz.qpic.cn/mmbiz_jpg/LUuerhGpzYOZI37ypufNRfc3eIcoViaRsicqiacG7a83Zd5q217cQurGSSAEcRsvD55E0v3VIqLCibgRITiaxe9eSjg/640?wx_fmt=jpeg&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>这样子，每一个事务去读取或者修改同一个记录时，只能操作已经提交了的数据，未提交的数据是不能读取到的。可重复，就这样实现了。</p><p>其实就是通过Read View的字段判断这行记录对自己是否可见，如果不可见的话再去找Undo Log里面记录的对自己可见的数据，然后操作就完事了。</p><p>怎么样，是不是很简单？</p><p>那么，我们再来看看MVCC如何实现提交读。</p><h3 id="mvcc如何实现提交读" tabindex="-1">MVCC如何实现提交读？ <a class="header-anchor" href="#mvcc如何实现提交读" aria-label="Permalink to &quot;MVCC如何实现提交读？&quot;">​</a></h3><p>我们先来回顾一下什么是提交读，提交读能够解决脏读这个并发一致性问题。脏读问题本质上就是一个事务读取到了另一个事务没有提交的内容。</p><p>那么Read View要如何解决这个问题呢？道理其实一样的。</p><p>假设事务A和事务B依然同一时刻启动，事务B将同一行的记录，也就是fancy的年龄又改成了25，但是并没有提交哦，所以此时事务A就会去读取这条记录的trx_id。 <img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208111552804.png" alt="image-20220811155212726" style="zoom:67%;"></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208111552281.png" alt="image-20220811155201167" style="zoom:67%;"><p>事务A查看到该记录的trx_id居然比事务A的Read View列表里面的creator_trx_id值大，并且修改这条记录的事务的trx_id存在于自己的m_ids列表里面，那么事务A就可以判断得到该记录是被另一条没有提交的事务修改的，所以它不会去读取这条数据的内容，事务A会继续通过Undo Log往下找第一条trx_id小于等于自己的事务id并且不在活跃事务列表m_ids里面的数据。</p><p>由此，便不会看到别的事务正在修改的数据，脏数据也不会产生。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208111549429.png" alt="image-20220811154948322" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208111550247.png" alt="image-20220811155007135" style="zoom:67%;"><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202208111551226.png" alt="image-20220811155145121" style="zoom:67%;"><h1 id="新特性" tabindex="-1">新特性 <a class="header-anchor" href="#新特性" aria-label="Permalink to &quot;新特性&quot;">​</a></h1><h2 id="设置持久化" tabindex="-1">设置持久化 <a class="header-anchor" href="#设置持久化" aria-label="Permalink to &quot;设置持久化&quot;">​</a></h2><p>MySQL 的设置可以在运行时通过 SET GLOBAL 命令来更改，但是这种更改只会临时生效，到下次启动时数据库又会从配置文件中读取。MySQL 8 新增了 SET PERSIST 命令，例如：</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">SET PERSIST max_connections </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">500</span><span style="color:#89DDFF;">;</span></span></code></pre></div><p>MySQL 会将该命令的配置保存到数据目录下的 mysqld-auto.cnf 文件中，下次启动时会读取该文件，用其中的配置来覆盖缺省的配置文件。</p><h2 id="utf-8-编码" tabindex="-1">UTF-8 编码 <a class="header-anchor" href="#utf-8-编码" aria-label="Permalink to &quot;UTF-8 编码&quot;">​</a></h2><p>从 MySQL 8 开始，数据库的缺省编码将改为 utf8mb4，这个编码包含了所有 emoji 字符。多少年来我们使用 MySQL 都要在编码方面小心翼翼，生怕忘了将缺省的 latin 改掉而出现乱码问题。从此以后就不用担心了。</p><h2 id="通用表表达式⭐⭐" tabindex="-1">通用表表达式⭐⭐ <a class="header-anchor" href="#通用表表达式⭐⭐" aria-label="Permalink to &quot;通用表表达式⭐⭐&quot;">​</a></h2><p>Common Table Expressions</p><p>复杂的查询会使用嵌入式表，例如：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> t1.</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;">, t2.</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> </span></span>
<span class="line"><span style="color:#A6ACCD;">  (</span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> col1 </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> table1) t1,</span></span>
<span class="line"><span style="color:#A6ACCD;">  (</span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> col2 </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> table2) t2;</span></span></code></pre></div><p>而有了 CTE，我们可以这样写：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">WITH</span></span>
<span class="line"><span style="color:#A6ACCD;">  t1 </span><span style="color:#F78C6C;">AS</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> col1 </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> table1),</span></span>
<span class="line"><span style="color:#A6ACCD;">  t2 </span><span style="color:#F78C6C;">AS</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> col2 </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> table2)</span></span>
<span class="line"><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> t1.</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;">, t2.</span><span style="color:#89DDFF;">*</span></span>
<span class="line"><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1, t2;</span></span></code></pre></div><p>这样看上去层次和区域都更加分明，改起来也更清晰的知道要改哪一部分。</p><p>关于 CTE 的更详细介绍请看官方文档。</p><blockquote><p><a href="https://dev.mysql.com/doc/refman/8.0/en/with.html" target="_blank" rel="noreferrer">https://dev.mysql.com/doc/refman/8.0/en/with.html</a></p></blockquote><h2 id="窗口函数" tabindex="-1">窗口函数 <a class="header-anchor" href="#窗口函数" aria-label="Permalink to &quot;窗口函数&quot;">​</a></h2><p>Window Functions</p><p>MySQL 被吐槽最多的特性之一就是缺少 rank() 函数，当需要在查询当中实现排名时，必须手写 @ 变量。但是从 8.0 开始，MySQL 新增了一个叫窗口函数的概念，它可以用来实现若干新的查询方式。</p><p>窗口函数有点像是 SUM()、COUNT() 那样的集合函数，但它并不会将多行查询结果合并为一行，而是将结果放回多行当中。也就是说，窗口函数是不需要 GROUP BY 的。</p><p><strong>假设我们有一张 “班级学生人数” 表：</strong></p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/e1IsRMuLpicLbCoxlGE1ficOoUfiadsLbkibymef5JQxaGHv9OjYuRosU3GqfRWuRicW47iciaOwK9IfDvv8HYXqiaxV3w/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>如果我要对班级人数从小到大进行排名，可以这样利用窗口函数：</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/e1IsRMuLpicLbCoxlGE1ficOoUfiadsLbkibgsniaJEAKwia1C0o6xrG1Ob077x3fSQLEvupR4JT1b9QqoGh28996ObA/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>在这里我们创建了名为 w 的 window，规定它对 stu_count 字段进行排序，然后在 select 子句中对 w 执行 rank() 方法，将结果输出为 rank 字段。</p><p>其实，window 的创建是可选的。例如我要在每一行中加入学生总数，则可以这样：</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/e1IsRMuLpicLbCoxlGE1ficOoUfiadsLbkibJ0SBnibR0femjxDPic3emCrtDnOs6uic9ZMHRxYoFeqRC9L25oLZr4ULA/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>这样做有什么用呢？这样我们就可以一次性将每个班级的学生人数占比查出来了：</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/e1IsRMuLpicLbCoxlGE1ficOoUfiadsLbkibAyv4Dr1U871D953q0ICKDbZ5dialJOtUC8QCL64jicAFD86HqKHdkanQ/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>这在以前可是要写一大段晦涩难懂的语句才能做到的哦！</p><h2 id="json特性" tabindex="-1">JSON特性 <a class="header-anchor" href="#json特性" aria-label="Permalink to &quot;JSON特性&quot;">​</a></h2><p>近几年来，nosql大行其道，json更是火的一塌糊涂。作为数据库的元老，mysql在5.7版本中添加了对json数据的支持。</p><p>能够将json数据直接存储到MySQL中首先创建一个数据库learnjson，并创建一张表json_start：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">table</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">json_start</span><span style="color:#A6ACCD;"> (</span></span>
<span class="line"><span style="color:#A6ACCD;">	id </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> auto_increment </span><span style="color:#C792EA;">PRIMARY KEY</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">not null</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">	person </span><span style="color:#F78C6C;">json</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">not NULL</span></span>
<span class="line"><span style="color:#A6ACCD;">);</span></span></code></pre></div><h3 id="增删改查" tabindex="-1">增删改查 <a class="header-anchor" href="#增删改查" aria-label="Permalink to &quot;增删改查&quot;">​</a></h3><h3 id="插入数据-1" tabindex="-1">插入数据 <a class="header-anchor" href="#插入数据-1" aria-label="Permalink to &quot;插入数据&quot;">​</a></h3><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">INSERT INTO</span><span style="color:#A6ACCD;"> json_start</span></span>
<span class="line"><span style="color:#F78C6C;">VALUES</span></span>
<span class="line"><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">{&quot;teacher&quot;:[{&quot;name&quot;:&quot;刘二&quot;,&quot;age&quot;:&quot;22&quot;,&quot;gender&quot;:&quot;女&quot;}]}</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">),</span></span>
<span class="line"><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">{&quot;student&quot;:[{&quot;name&quot;:&quot;张三&quot;,&quot;age&quot;:&quot;18&quot;,&quot;gender&quot;:&quot;男&quot;}]}</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">),</span></span>
<span class="line"><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">{&quot;coder&quot;:[{&quot;name&quot;:&quot;张三&quot;,&quot;age&quot;:&quot;18&quot;,&quot;gender&quot;:&quot;男&quot;}]}</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">);</span></span></code></pre></div><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> json_start;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220404145333148.png" alt="image-20220404145333148" style="zoom:67%;"><p>需要注意的是，在插入json类型的字符串时，mysql会对json字符串进行格式校验，如果格式有误，就无法插入，并且默认情况下，json数据的大小也是有限制的，默认大小和LONGTEXT ,LONGBLOB 一样，同时他还受限于mysql配置项：max_allowed_packet. 的限制（默认为4M）</p><p>再插入一条数据</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">INSERT INTO</span><span style="color:#A6ACCD;"> json_start </span><span style="color:#F78C6C;">VALUES</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">[{&quot;name&quot;:&quot;奔驰&quot;,&quot;model&quot;:&quot;C260&quot;,&quot;price&quot;:&quot;200RMB&quot;},</span></span>
<span class="line"><span style="color:#C3E88D;">{&quot;name&quot;:&quot;劳斯莱斯&quot;,&quot;model&quot;:&quot;定制版&quot;,&quot;price&quot;:&quot;166RMB&quot;},</span></span>
<span class="line"><span style="color:#C3E88D;">{&quot;name&quot;:&quot;奥迪&quot;,&quot;model&quot;:&quot;A6&quot;,&quot;price&quot;:&quot;200000000RMB&quot;}]</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"><span style="color:#A6ACCD;">);</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220404145527847.png" alt="image-20220404145527847" style="zoom:80%;"><p>你会发现，虽然最后一条记录的json内容和其他两条记录的类容完全不一样甚至结构都不一样，但是依然能插入成功，因为mysql在插入时只对格式进行校验，格式通过了，就当成字符串存储，并不会考虑与其他记录是否保持一致，事实上这么做没必要。但这同时引入了一个使用时需要注意的事项，就是在定义表的时候就必须尽可能的表以及字段的功能，数据结构明确清楚，并且避免一个字段多种数据混合存储。</p><h3 id="更新数据" tabindex="-1">更新数据 <a class="header-anchor" href="#更新数据" aria-label="Permalink to &quot;更新数据&quot;">​</a></h3><h4 id="直接追加" tabindex="-1">直接追加 <a class="header-anchor" href="#直接追加" aria-label="Permalink to &quot;直接追加&quot;">​</a></h4><p>mysqljson数据跟新操作根据json数据的类型范围分为列表操作和对象操作两种类型，都可以直接说那个merge操作。下面我们试着给第一条记录追加一个manager属性，很显然这是一个对象操作,执行语句如下：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;"># person是字段名</span></span>
<span class="line"><span style="color:#F78C6C;">UPDATE</span><span style="color:#A6ACCD;"> json_start </span><span style="color:#F78C6C;">set</span></span>
<span class="line"><span style="color:#A6ACCD;">person </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> json_MERGE(person,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">{&quot;manager&quot;:[{&quot;name&quot;:&quot;laoda&quot;,&quot;age&quot;:&quot;38&quot;,&quot;gender&quot;:&quot;男&quot;}]}</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220404150041412.png" alt="image-20220404150041412" style="zoom:67%;"><p>原理就是将原来的json对象和要添加的对象合并，稍后将会描述这其中的合并规则。</p><h4 id="追加到数组" tabindex="-1">追加到数组 <a class="header-anchor" href="#追加到数组" aria-label="Permalink to &quot;追加到数组&quot;">​</a></h4><p>追加到数组可以使用JSON_APPEND()(mysql 5.7.9或更早的版本) 或者JSON_ARRAY_APPEND()方法，该操作将指定的对象添加到数组末尾，例如：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">update</span><span style="color:#A6ACCD;"> json_start</span></span>
<span class="line"><span style="color:#F78C6C;">set</span></span>
<span class="line"><span style="color:#A6ACCD;">person </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> json_ARRAY_APPEND(person,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">$</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">                           </span><span style="color:#82AAFF;">JSON_OBJECT</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">玛莎拉蒂</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">model</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">ah</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">price</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">168RMB</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">))</span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">3</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220404150433417.png" alt="image-20220404150433417" style="zoom:67%;"><h4 id="修改json属性" tabindex="-1">修改json属性 <a class="header-anchor" href="#修改json属性" aria-label="Permalink to &quot;修改json属性&quot;">​</a></h4><p>mysql提供一个非常灵活的本地方法：json_set(doc,path,value),其中doc为要修改的json列，path为要修改的属性的对象定位表达式，value为新值，例如：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">UPDATE</span><span style="color:#A6ACCD;"> json_start </span><span style="color:#F78C6C;">set</span></span>
<span class="line"><span style="color:#A6ACCD;">person </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> json_set(person,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">$.teacher[0].name</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">张三三三三三</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220404150933209.png" alt="image-20220404150933209" style="zoom:67%;"><p>需要注意的是，当使用json_set（）方法去修改一整个对象或者数组时，mysql或将value当成字符串来解析保存，当你的value中包含”时，或自动进行转义，这样存储起来很浪费空间，同时也会产生问题，如果需要修改整个对象，建议使用Json_object(key，value，key2,value2....)来格式化你的对象，例如：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">UPDATE</span><span style="color:#A6ACCD;"> json_start</span></span>
<span class="line"><span style="color:#F78C6C;">set</span></span>
<span class="line"><span style="color:#A6ACCD;">person </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> json_set(person,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">$.teacher[0]</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">                  </span><span style="color:#82AAFF;">JSON_OBJECT</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">age</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">18</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">张sisisisi</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">gender</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">男</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">))</span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220404151221565.png" alt="image-20220404151221565" style="zoom:67%;"><h3 id="删除记录" tabindex="-1">删除记录 <a class="header-anchor" href="#删除记录" aria-label="Permalink to &quot;删除记录&quot;">​</a></h3><p>删除记录使用JSON_REMOVE(doc,path1，path2,...)方法,例如：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">update</span><span style="color:#A6ACCD;"> json_start </span><span style="color:#F78C6C;">set</span><span style="color:#A6ACCD;"> person </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> json_REMOVE(person,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">$[0]</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">3</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#F78C6C;">update</span><span style="color:#A6ACCD;"> json_start </span><span style="color:#F78C6C;">set</span><span style="color:#A6ACCD;"> person </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> json_REMOVE(person,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">$.coder[0]</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><h3 id="查询记录" tabindex="-1">查询记录 <a class="header-anchor" href="#查询记录" aria-label="Permalink to &quot;查询记录&quot;">​</a></h3><p>查询所有的属性key,使用json_keys(doc)方法：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,json_keys(person) </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> json_start;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220404151943644.png" alt="image-20220404151943644" style="zoom:67%;"><p>查询指定的记录中的某个属性或者值，使用Json_extract(doc,path)方法，例如：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,json_extract(person,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">$.teacher[0].name</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">name</span></span>
<span class="line"><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> json_start</span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220404152036057.png" alt="image-20220404152036057" style="zoom:67%;"><p>或者</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,json_extract(person,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">$.teacher[0]</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> json_start</span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220404152118873.png" alt="image-20220404152118873" style="zoom:67%;"><p>当然，你也可以使用通配符‘*’来实现多值查询，例如：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,json_extract(person,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">$.*[*].*</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">) person</span></span>
<span class="line"><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> json_start</span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220404152518746.png" alt="image-20220404152518746" style="zoom:67%;"><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,json_extract(person,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">$.teacher[*].name</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">name</span></span>
<span class="line"><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> json_start</span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220404152539842.png" alt="image-20220404152539842" style="zoom:67%;"><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,json_extract(person,</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">$.*[*].name</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">name</span></span>
<span class="line"><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> json_start</span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220404152623121.png" alt="image-20220404152623121" style="zoom:67%;"><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id, person </span><span style="color:#89DDFF;">-&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">$.*[*].name</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> json_start;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220404154148298.png" alt="image-20220404154148298" style="zoom:67%;"><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span></span>
<span class="line"><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> json_start</span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> person </span><span style="color:#89DDFF;">-&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">$.manager[0].name</span><span style="color:#89DDFF;">&#39;</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">laoda</span><span style="color:#89DDFF;">&#39;</span></span></code></pre></div><h3 id="虚拟列" tabindex="-1">虚拟列 <a class="header-anchor" href="#虚拟列" aria-label="Permalink to &quot;虚拟列&quot;">​</a></h3><p>直接where查询会不走索引，用虚拟列走索引快</p><p>注意：<strong>在更新json中的字段时，虚拟列中的数据也会对应更新</strong></p><p>准备数据</p><p>注意：表名后面一定要加上字段名，不然新增虚拟列再插入数据会出错</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">INSERT INTO</span><span style="color:#A6ACCD;"> json_start(id,person)</span></span>
<span class="line"><span style="color:#F78C6C;">VALUES</span></span>
<span class="line"><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">{&quot;name&quot;:&quot;刘二&quot;,&quot;age&quot;:&quot;22&quot;,&quot;gender&quot;:&quot;女&quot;}</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">),</span></span>
<span class="line"><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">{&quot;name&quot;:&quot;张三&quot;,&quot;age&quot;:&quot;18&quot;,&quot;gender&quot;:&quot;男&quot;}</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">),</span></span>
<span class="line"><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">{&quot;name&quot;:&quot;张三&quot;,&quot;age&quot;:&quot;18&quot;,&quot;gender&quot;:&quot;男&quot;}</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">);</span></span></code></pre></div><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> json_start;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220404155458839.png" alt="image-20220404155458839" style="zoom:67%;"><p>根据提取的name生成字段</p><p>字段只能读，不能写</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 创建虚拟列，允许为空</span></span>
<span class="line"><span style="color:#F78C6C;">alter</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">table</span><span style="color:#A6ACCD;"> json_start</span></span>
<span class="line"><span style="color:#F78C6C;">add</span><span style="color:#A6ACCD;"> column </span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">32</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#F78C6C;">generated</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">always</span></span>
<span class="line"><span style="color:#F78C6C;">as</span><span style="color:#A6ACCD;"> (json_unquote(json_extract(person,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">$.name</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">)))</span></span>
<span class="line"><span style="color:#A6ACCD;">virtual </span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;"> ;</span></span></code></pre></div><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> json_start;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220404160139351.png" alt="image-20220404160139351" style="zoom:67%;"><p>在虚拟列上加索引</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">n1</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> json_start(</span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;">);</span></span></code></pre></div><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span></span>
<span class="line"><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> json_start</span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> person </span><span style="color:#89DDFF;">-&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">$.name</span><span style="color:#89DDFF;">&#39;</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">刘二</span><span style="color:#89DDFF;">&#39;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220404160558085.png" alt="image-20220404160558085" style="zoom:67%;"><p>数据已经走索引了</p><h1 id="sql优化⭐" tabindex="-1">SQL优化⭐ <a class="header-anchor" href="#sql优化⭐" aria-label="Permalink to &quot;SQL优化⭐&quot;">​</a></h1><h2 id="插入数据-2" tabindex="-1">插入数据 <a class="header-anchor" href="#插入数据-2" aria-label="Permalink to &quot;插入数据&quot;">​</a></h2><p><a href="https://www.cnblogs.com/datiangou/p/10296282.html" target="_blank" rel="noreferrer">MySQL插入性能优化 - 大天狗子 - 博客园 (cnblogs.com)</a></p><blockquote><ul><li>最快的当然是直接copy数据库表的数据文件(版本和平台最好要相同或相似才可以这样做)</li><li>设置innodb_flush_log_at_trx commit=0,相对于 innodb flush log at trx commit=1可以十分明显地提升导入速度</li><li><strong>使用load data local infile提速明显</strong></li><li>修改参数bulk insert buffer size，<strong><code>调大批量插入的缓存</code></strong></li><li>合并多条INSERT 为一条，如 INSERT INTO t values(a,b,e),(d,e,f) ...<strong>.<code>手动使用事务</code></strong></li></ul></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303012047556.png" alt="image-20230301204746300" style="zoom:80%;"><h3 id="批量插入" tabindex="-1">批量插入 <a class="header-anchor" href="#批量插入" aria-label="Permalink to &quot;批量插入&quot;">​</a></h3><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">insert into</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">admin</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">values</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">赵1</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">12341</span><span style="color:#A6ACCD;">),(</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">赵1</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">12341</span><span style="color:#A6ACCD;">),(</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">赵1</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">12341</span><span style="color:#A6ACCD;">);</span></span></code></pre></div><h3 id="手动提交事务" tabindex="-1">手动提交事务 <a class="header-anchor" href="#手动提交事务" aria-label="Permalink to &quot;手动提交事务&quot;">​</a></h3><p>开启一个事务，批量操作完了才提交事务，而不是，操作一次就提交一次，这样io太高，插入太慢。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">start transaction</span><span style="color:#A6ACCD;"> ;</span></span>
<span class="line"><span style="color:#F78C6C;">insert into</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">admin</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">values</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">赵1</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">12341</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"><span style="color:#F78C6C;">insert into</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">admin</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">values</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">赵2</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">12342</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"><span style="color:#F78C6C;">insert into</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">admin</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">values</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">赵3</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">12343</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"><span style="color:#F78C6C;">commit</span><span style="color:#A6ACCD;"> ;</span></span></code></pre></div><h3 id="主键顺序插入" tabindex="-1">主键顺序插入 <a class="header-anchor" href="#主键顺序插入" aria-label="Permalink to &quot;主键顺序插入&quot;">​</a></h3><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">insert into</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">admin</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">values</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">赵1</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">12341</span><span style="color:#A6ACCD;">),(</span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">赵1</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">12341</span><span style="color:#A6ACCD;">),(</span><span style="color:#F78C6C;">3</span><span style="color:#A6ACCD;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">赵1</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">12341</span><span style="color:#A6ACCD;">);</span></span></code></pre></div><h3 id="大批量插入" tabindex="-1">大批量插入 <a class="header-anchor" href="#大批量插入" aria-label="Permalink to &quot;大批量插入&quot;">​</a></h3><blockquote><p>如果一次性需要插入大批量数据，<strong>使用insert语句插入性能较低</strong>。<strong>load data 语句能快速将一个文本文件的内容导入到对应的数据库表中（一般文本的一行对应表的一条记录）</strong>。数据库应用程序开发中，涉及大批量数据需要插入时，使用 load data 语句的效率比一般的 insert 语句的高很多</p></blockquote><h4 id="数据格式" tabindex="-1">数据格式 <a class="header-anchor" href="#数据格式" aria-label="Permalink to &quot;数据格式&quot;">​</a></h4><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303012056242.png" alt="image-20230301205641963" style="zoom:67%;"><h4 id="表结构" tabindex="-1">表结构 <a class="header-anchor" href="#表结构" aria-label="Permalink to &quot;表结构&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">table</span><span style="color:#A6ACCD;"> `</span><span style="color:#82AAFF;">tb_user1</span><span style="color:#A6ACCD;">` (</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">11</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">not null</span><span style="color:#A6ACCD;"> auto_increment,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">username</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">50</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">not null</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">password</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">50</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">not null</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">20</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">not null</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">birthday</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">date</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">sex</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">char</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">) </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#C792EA;">primary key</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">),</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">unique</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">key</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">unique_user_username</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">username</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">) engine</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">innodb </span><span style="color:#C792EA;">default</span><span style="color:#A6ACCD;"> charset</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">utf8 ;</span></span></code></pre></div><h4 id="插入数据⭐" tabindex="-1">插入数据⭐ <a class="header-anchor" href="#插入数据⭐" aria-label="Permalink to &quot;插入数据⭐&quot;">​</a></h4><p>此时可以使用MySQL数据库提供的load指令进行插入。操作如下：</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img/image-20220410114546499.png" alt="image-20220410114546499"></p><p>以管理员进入cmd</p><div class="language-apl"><button title="Copy Code" class="copy"></button><span class="lang">apl</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">mysql </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">u root </span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">p </span><span style="color:#89DDFF;">--</span><span style="color:#A6ACCD;">local</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">infile</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">1</span></span></code></pre></div><p>进行开启</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 设置全局参数local_infile为1，开启从本地加载文件导入数据的开关</span></span>
<span class="line"><span style="color:#A6ACCD;">set global local_infile=1;</span></span>
<span class="line"><span style="color:#A6ACCD;">show global variables like &#39;local_infile&#39;;</span></span></code></pre></div><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">use itcast</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 注意文件路径的/，只能这么写，不然可能会找不到文件</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 分隔符是逗号，换行符是/n</span></span>
<span class="line"><span style="color:#A6ACCD;">load data </span></span>
<span class="line"><span style="color:#A6ACCD;">local infile &#39;/var/lib/mysql-files/load_user_100w_sort.sql&#39; </span></span>
<span class="line"><span style="color:#A6ACCD;">into table tb_user1 fields terminated by &#39;,&#39; lines terminated by &#39;\n&#39;;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303012101117.png" alt="image-20230301210143946" style="zoom:80%;"><h3 id="大批量导出" tabindex="-1">大批量导出 <a class="header-anchor" href="#大批量导出" aria-label="Permalink to &quot;大批量导出&quot;">​</a></h3><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show variables </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">%secure_file_priv%</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211210032.png" alt="image-20220921121015886" style="zoom:80%;"><p>导出必须导出到安全目录中，不然会出错</p><ul><li>FIELDS TERMINATED：分隔符是逗号</li><li>OPTIONALLY ENCLOSED：用双引号包括</li><li>LINES TERMINATED：换行</li><li>tb_sku1.sql后缀名无所谓，也可以是txt</li></ul><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user1</span></span>
<span class="line"><span style="color:#F78C6C;">into</span><span style="color:#A6ACCD;"> outfile </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">/var/lib/mysql-files/tb_user1.sql</span><span style="color:#89DDFF;">&quot;</span></span>
<span class="line"><span style="color:#A6ACCD;">fields terminated </span><span style="color:#F78C6C;">by</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">,</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> optionally enclosed </span><span style="color:#F78C6C;">by</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">&quot;</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> lines terminated </span><span style="color:#F78C6C;">by</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">\n</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211244071.png" alt="image-20220921124403947" style="zoom:80%;"><p>进入目录查看：/var/lib/mysql-files</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303012110881.png" alt="image-20230301211051684" style="zoom:80%;"><h3 id="影响插入因素" tabindex="-1">影响插入因素 <a class="header-anchor" href="#影响插入因素" aria-label="Permalink to &quot;影响插入因素&quot;">​</a></h3><h4 id="缓冲区" tabindex="-1">缓冲区 <a class="header-anchor" href="#缓冲区" aria-label="Permalink to &quot;缓冲区&quot;">​</a></h4><p>增大缓冲区：原来第一个8M，第二个48M</p><div class="language-ini"><button title="Copy Code" class="copy"></button><span class="lang">ini</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F07178;">innodb_buffer_pool_size</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">80M</span></span>
<span class="line"><span style="color:#F07178;">innodb_log_file_size</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">100M</span></span></code></pre></div><h4 id="max-allowed-packet" tabindex="-1">max_allowed_packet <a class="header-anchor" href="#max-allowed-packet" aria-label="Permalink to &quot;max_allowed_packet&quot;">​</a></h4><h5 id="_1、sql语句的大小限制" tabindex="-1">1、SQL语句的大小限制 <a class="header-anchor" href="#_1、sql语句的大小限制" aria-label="Permalink to &quot;1、SQL语句的大小限制&quot;">​</a></h5><p>配置文件里有 <code>max_allowed_packet</code> 这个参数控制通信的 packet 大小。MySQL默认的SQL语句的最大限制是1M（mysql5.7的客户端默认是16M，服务端默认是4M），可以根据设置查看。官方解释是适当增大 <code>max_allowed_packet</code> 参数可以使client端到server端传递大数据时，系统能够分配更多的扩展内存来处理。</p><h5 id="_2、查看服务器上的参数" tabindex="-1">2、查看服务器上的参数 <a class="header-anchor" href="#_2、查看服务器上的参数" aria-label="Permalink to &quot;2、查看服务器上的参数&quot;">​</a></h5><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show variables </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%max_allowed_packet%</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.10.30/202209232033242.png" alt="image-20220923203348158" style="zoom:80%;"><p><code>4194304字节 = 4M</code> ，也就是规定大小不能超过4M</p><h5 id="_3、计算一次能插入的最大行记录" tabindex="-1">3、计算一次能插入的最大行记录 <a class="header-anchor" href="#_3、计算一次能插入的最大行记录" aria-label="Permalink to &quot;3、计算一次能插入的最大行记录&quot;">​</a></h5><p>1M计算的话，<code>(1024*1024)/52 ≈ 20165</code> ，为了防止溢出，最大可一次性插入20000条（根据自己的配置和sql语句大小计算）。那么4M的话就是：<code>20000 *4 = 80000</code> 也就是8W条。</p><blockquote><p>个人感觉，最佳大小是<code>max_allowed_packet</code>的一半，也就是极限能插入64W，选用32W也许性能会更好一些，同时也不会对mysql的其他操作产生太大的影响。</p></blockquote><h4 id="缓冲区大小" tabindex="-1">缓冲区大小 <a class="header-anchor" href="#缓冲区大小" aria-label="Permalink to &quot;缓冲区大小&quot;">​</a></h4><p>在分析源码的过程中，有一句话：如果<code>buffer pool</code>余量不足25%，插入失败，返回<code>DB_LOCK_TABLE_FULL</code>。这个错误并不是直接报错：<code>max_allowed_packet</code> 不够大之类的，这个错误是因为对于innodb引擎来说，一次插入是涉及到事务和锁的，在插入索引的时候，要判断缓冲区的剩余情况，所以插入并不能仅仅只考虑<code>max_allowed_packet</code>的问题，也要考虑到缓冲区的大小。</p><p>也就是说，插入缓冲受到缓冲池大小的影响，缓冲池大小为：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">mysql</span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> show variables </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">innodb_buffer_pool_size</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#89DDFF;">+</span><span style="color:#676E95;font-style:italic;">-------------------------+-----------+</span></span>
<span class="line"><span style="color:#A6ACCD;">| Variable_name           | </span><span style="color:#F78C6C;">Value</span><span style="color:#A6ACCD;">     |</span></span>
<span class="line"><span style="color:#89DDFF;">+</span><span style="color:#676E95;font-style:italic;">-------------------------+-----------+</span></span>
<span class="line"><span style="color:#A6ACCD;">| innodb_buffer_pool_size | </span><span style="color:#F78C6C;">134217728</span><span style="color:#A6ACCD;"> |</span></span>
<span class="line"><span style="color:#89DDFF;">+</span><span style="color:#676E95;font-style:italic;">-------------------------+-----------+</span></span></code></pre></div><p>换算后的结果为：128M，也就是说，<a href="http://mp.weixin.qq.com/s?__biz=MzI4Njc5NjM1NQ==&amp;mid=2247495436&amp;idx=1&amp;sn=c6d3be347af53e2a570da5d4c868c746&amp;chksm=ebd5d020dca2593665cc5ac9a59ca83e6d6e413542423c0584a5c455134a9aac359fbcbdb08b&amp;scene=21#wechat_redirect" target="_blank" rel="noreferrer">插入缓存</a>最多可以占用64M的缓冲区大小。这个大小要超过咱们设置的sql语句大小，所以可以忽略不计。</p><blockquote><p>我们都知道，在InnoDB引擎上进行插入操作时，一般需要按照主键顺序进行插入，这样才能获得较高的插入性能。当一张表中存在非聚簇的且不唯一的索引时，在插入时，数据页的存放还是按照主键进行顺序存放，但是对于非聚簇索引叶节点的插入不再是顺序的了，这时就需要离散的访问非聚簇索引页，由于随机读取的存在导致插入操作性能下降。</p></blockquote><h4 id="使用事务提升效率" tabindex="-1">使用事务提升效率 <a class="header-anchor" href="#使用事务提升效率" aria-label="Permalink to &quot;使用事务提升效率&quot;">​</a></h4><p>还有一种说法，使用事务可以提高数据的插入效率，这是因为进行一个<code>INSERT</code>操作时，MySQL内部会建立一个事务，在事务内才进行真正插入处理操作。通过使用事务可以减少创建事务的消耗，所有插入都在执行后才进行提交操作。大概如下：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">START TRANSACTION</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#F78C6C;">INSERT INTO</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">insert_table</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">datetime</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">uid</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">content</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">type</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">) </span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">VALUES</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">0</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">userid_0</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">content_0</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">0</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"><span style="color:#F78C6C;">INSERT INTO</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">insert_table</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">datetime</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">uid</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">content</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">type</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">) </span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">VALUES</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">1</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">userid_1</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">content_1</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">...</span></span>
<span class="line"><span style="color:#F78C6C;">COMMIT</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>这种写法和批量写入的效果差不多，只不过sql语句还是单句的，然后统一提交。一个瓶颈是SQL语句的大小，一个瓶颈是事务的大小。当我们在提交sql的时候，首先是受到sql大小的限制，其次是受到事务大小的限制。在开启事务的情况下使用批量插入，会节省不少事务的开销，如果要追求极致的速度的话，建议是开着事务插入的。</p><blockquote><p>不过需要注意一下，内存是有限且共享的，如果批量插入占用太多的事务内存，那么势必会对其他的业务操作等有一定的影响。</p></blockquote><h4 id="索引影响插入性能" tabindex="-1">索引影响插入性能 <a class="header-anchor" href="#索引影响插入性能" aria-label="Permalink to &quot;索引影响插入性能&quot;">​</a></h4><blockquote><p>如果表中存在多个字段索引，当对表中的数据进行增加、删除和修改的时候，索引也要动态的维护。这样就降低了数据的插入速度。对于普通的数据表，主键索引是肯定要有的，想要加快性能的话，就是要有序插入，每次插入记录都在索引的最后面，索引的定位效率很高，并且对索引调整较小。</p><p>如果插入的记录在索引中间，需要B+tree进行分裂合并等处理，会消耗比较多计算资源，并且插入记录的索引定位效率会下降，数据量较大时会有频繁的磁盘操作。</p></blockquote><h2 id="主键优化" tabindex="-1">主键优化 <a class="header-anchor" href="#主键优化" aria-label="Permalink to &quot;主键优化&quot;">​</a></h2><p>主键设计原则</p><blockquote><p>➢ 满足业务需求的情况下，<strong>尽量降低主键的长度</strong>。</p><p>➢ 插入数据时，<strong>尽量选择顺序插入</strong>，<strong>选择使用AUTO_INCREMENT自增主键</strong>。</p><p>➢ 尽量<strong>不要使用UUID做主键或者是其他自然主键</strong>，如<strong>身份证号</strong>。</p><p>➢ 业务操作时，<strong>避免对主键的修改</strong>。</p></blockquote><h2 id="order-by⭐" tabindex="-1">order by⭐ <a class="header-anchor" href="#order-by⭐" aria-label="Permalink to &quot;order by⭐&quot;">​</a></h2><blockquote><p>Using filesort:通过表的索引或全表扫描，读取满足条件的数据行，然后在排序缓冲区sort buffer中完成排序操作，所有不是通过索引直接返回排序结果的排序都叫FileSort排序</p><p>Using index:通过有序索引顺序扫描直接返回有序数据，这种情况即为using index，不需要额外排序，操作效率高</p><p>注意事项：优先考虑Using index，将Using filesort改造成Using index</p></blockquote><h3 id="表结构-1" tabindex="-1">表结构 <a class="header-anchor" href="#表结构-1" aria-label="Permalink to &quot;表结构&quot;">​</a></h3><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">table</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">tb_user</span><span style="color:#A6ACCD;">(</span></span>
<span class="line"><span style="color:#A6ACCD;">   id </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">primary key</span><span style="color:#A6ACCD;"> auto_increment comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">主键</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">50</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">not null</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">用户名</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">   phone </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">11</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">not null</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">手机号</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">   email </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">) comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">邮箱</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">   profession </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">11</span><span style="color:#A6ACCD;">) comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">专业</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">   age </span><span style="color:#F78C6C;">tinyint</span><span style="color:#A6ACCD;"> unsigned comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">年龄</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">   gender </span><span style="color:#C792EA;">char</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">) comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">性别 , 1: 男, 2: 女</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">   </span><span style="color:#F78C6C;">status</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">char</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">) comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">状态</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">   createtime </span><span style="color:#F78C6C;">datetime</span><span style="color:#A6ACCD;"> comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">创建时间</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"><span style="color:#A6ACCD;">) comment </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">系统用户表</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 创建索引时，根据profession, age,status</span></span>
<span class="line"><span style="color:#A6ACCD;">create index idx_user_pro_age_sta on tb_user(profession, age,status);</span></span></code></pre></div><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 当前是没用到索引，出现Using filesort，效率是比较低的</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,age,phone </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> itcast.tb_user </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> age;</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,age,phone </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> itcast.tb_user </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> age,phone;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211750093.png" alt="image-20220921175033994" style="zoom:80%;"><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 根据age和phone创建联合索引，下面两条查询语句都用到了索引</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_age_phone</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> tb_user(age,phone);</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,age,phone </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> itcast.tb_user </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> age;</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,age,phone </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> itcast.tb_user </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> age,phone;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211751458.png" alt="image-20220921175156364" style="zoom:80%;"><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 出现了反向扫描索引</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,age,phone </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> itcast.tb_user </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> age </span><span style="color:#F78C6C;">desc</span><span style="color:#A6ACCD;"> ,phone </span><span style="color:#F78C6C;">desc</span><span style="color:#A6ACCD;"> ;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211753334.png" alt="image-20220921175345244" style="zoom:80%;"><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 排序时违背了创建时的顺序，最左前缀法则，因此有了Using filesort</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,age,phone </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> itcast.tb_user </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> phone ,age;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 一个升序，一个降序，这样就会出现using filesort，效率降低</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,age,phone </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> itcast.tb_user </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> age </span><span style="color:#F78C6C;">asc</span><span style="color:#A6ACCD;"> ,phone </span><span style="color:#F78C6C;">desc</span><span style="color:#A6ACCD;"> ;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211755622.png" alt="image-20220921175503532" style="zoom:80%;"><p>创建索引时添加排序(这样都能使用索引排序了)</p><p>前提：使用覆盖索引</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303020923579.png" alt="image-20230302092359333" style="zoom:80%;"><p>注意：mysql8才支持建立降序索引</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 创建索引(birthday,sex),同样全部生效</span></span>
<span class="line"><span style="color:#A6ACCD;">create index idx_bxd on tb_user(age asc ,phone desc);</span></span>
<span class="line"><span style="color:#A6ACCD;">explain select id,age,phone from itcast.tb_user order by age asc ,phone desc ;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211759874.png" alt="image-20220921175902777" style="zoom:80%;"><h3 id="优化方案" tabindex="-1">优化方案 <a class="header-anchor" href="#优化方案" aria-label="Permalink to &quot;优化方案&quot;">​</a></h3><blockquote><p>➢<strong>根据排序字段建立合适的索引，多字段排序时，也遵循最左前缀法则</strong>。</p><p>➢尽量使用覆盖索引。</p><p>➢多字段排序 一个升序一个降序，此时需要注意联合索引在创建时的规则(ASC/DESC)</p><p>➢如果不可避免的出现 ，大数据量排序时，可以适当增大排序缓冲区大小sort_buffer_size(默认256k)</p></blockquote><h2 id="group-by优化" tabindex="-1">group by优化 <a class="header-anchor" href="#group-by优化" aria-label="Permalink to &quot;group by优化&quot;">​</a></h2><blockquote><p>分组操作，我们主要来看看索引对于分组操作的影响</p><p>在分组操作时，可以通过索引来提高效率，分组操作时，索引的使用也是满足最左前缀法则的</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303020925484.png" alt="image-20230302092518302" style="zoom:80%;"><p>首先我们先将 tb_user 表的索引全部删除掉 。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show indexes </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 只留下主键索引</span></span>
<span class="line"><span style="color:#F78C6C;">drop</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> idx_user_pro_age_sta </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> tb_user;</span></span>
<span class="line"><span style="color:#F78C6C;">drop</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> idx_age_phone </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> tb_user;</span></span>
<span class="line"><span style="color:#F78C6C;">drop</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> idx_bxd </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> tb_user;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209212014577.png" alt="image-20220921201400485" style="zoom:80%;"><p>接下来，在没有索引的情况下，执行如下SQL，查询执行计划：并没有用到索引，而且是Using temporary，性能较低</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> profession , </span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user </span><span style="color:#F78C6C;">group by</span><span style="color:#A6ACCD;"> profession ;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209212017770.png" alt="image-20220921201753679" style="zoom:80%;"><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 然后，我们在针对于 profession ， age， status 创建一个联合索引</span></span>
<span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_user_pro_age_sta</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> tb_user(profession , age , </span><span style="color:#F78C6C;">status</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 紧接着，再执行前面相同的SQL查看执行计划。</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> profession , </span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user </span><span style="color:#F78C6C;">group by</span><span style="color:#A6ACCD;"> profession ;</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> profession , </span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user </span><span style="color:#F78C6C;">group by</span><span style="color:#A6ACCD;"> profession,age;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209212016052.png" alt="image-20220921201616961" style="zoom:80%;"><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> age,</span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user </span><span style="color:#F78C6C;">group by</span><span style="color:#A6ACCD;"> age;</span></span></code></pre></div><blockquote><p>我们发现，如果仅仅根据age分组，就会出现 Using temporary ；而如果是 根据profession,age两个字段同时分组，则不会出现 Using temporary。原因是因为对于分组操作，在联合索引中，也是符合最左前缀法则的。</p></blockquote><p>所以，在分组操作中，我们需要通过以下两点进行优化，以提升性能：</p><blockquote><p>A. 在分组操作时，可以通过索引来提高效率。</p><p>B. 分组操作时，索引的使用也是满足最左前缀法则的</p></blockquote><h2 id="limit优化" tabindex="-1">limit优化 <a class="header-anchor" href="#limit优化" aria-label="Permalink to &quot;limit优化&quot;">​</a></h2><h3 id="深分页为什么会变慢" tabindex="-1">深分页为什么会变慢 <a class="header-anchor" href="#深分页为什么会变慢" aria-label="Permalink to &quot;深分页为什么会变慢&quot;">​</a></h3><blockquote><p>limit语句会先扫描offset+n行，然后再丢弃掉前offset行，返回后n行数据。也就是说**<code>limit 100000,10</code><strong>，就会扫描100010行，而</strong><code>limit 0,10</code><strong>，只扫描10行。</strong><code>limit 100000,10</code>** 扫描更多的行数，也意味着<strong>回表</strong>更多的次数。在数据量比较大时，如果进行limit分页查询，在查询时，越往后，分页查询效率越低。我们一起来看看执行limit分页查询耗时对比：</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.3.30/202303020932454.png" alt="image-20230302093247252" style="zoom:67%;"><blockquote><p>通过测试我们会看到，<strong>越往后，分页查询效率越低，这就是分页查询的问题所在</strong>。因为，<strong>当在进行分页查询时，如果执行 limit 2000000,10 ，此时需要MySQL排序前2000010 记录，仅仅返回 2000000 - 2000010 的记录，其他记录丢弃，查询排序的代价非常大</strong> 。</p></blockquote><h3 id="数据准备-1" tabindex="-1">数据准备 <a class="header-anchor" href="#数据准备-1" aria-label="Permalink to &quot;数据准备&quot;">​</a></h3><h4 id="表结构-2" tabindex="-1">表结构 <a class="header-anchor" href="#表结构-2" aria-label="Permalink to &quot;表结构&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">TABLE</span><span style="color:#A6ACCD;"> `</span><span style="color:#82AAFF;">account</span><span style="color:#A6ACCD;">` (</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">NOT NULL</span><span style="color:#A6ACCD;"> AUTO_INCREMENT,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">varchar</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">35</span><span style="color:#A6ACCD;">) </span><span style="color:#C792EA;">DEFAULT</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">NULL</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">money</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> double </span><span style="color:#C792EA;">DEFAULT</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">NULL</span><span style="color:#A6ACCD;">,</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#C792EA;">PRIMARY KEY</span><span style="color:#A6ACCD;"> (</span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">)</span></span></code></pre></div><h4 id="制造数据" tabindex="-1">制造数据 <a class="header-anchor" href="#制造数据" aria-label="Permalink to &quot;制造数据&quot;">​</a></h4><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">procedure</span><span style="color:#A6ACCD;"> p1(</span><span style="color:#F78C6C;">in</span><span style="color:#A6ACCD;"> n </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#F78C6C;">begin</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">DECLARE</span><span style="color:#A6ACCD;"> i </span><span style="color:#C792EA;">INT</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">DEFAULT</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">start transaction</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">repeat</span></span>
<span class="line"><span style="color:#A6ACCD;">       </span><span style="color:#F78C6C;">set</span><span style="color:#A6ACCD;"> i </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> i</span><span style="color:#89DDFF;">+</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">       </span><span style="color:#F78C6C;">insert into</span><span style="color:#A6ACCD;"> account(id,</span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;">,</span><span style="color:#C792EA;">money</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">values</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">null</span><span style="color:#A6ACCD;">,</span><span style="color:#82AAFF;">concat</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">刘备</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">,n), n</span><span style="color:#89DDFF;">+</span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">       until i </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> n</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">end</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">repeat</span><span style="color:#A6ACCD;"> ;</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">commit</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#F78C6C;">end</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 清空表(数据用完删了)</span></span>
<span class="line"><span style="color:#F78C6C;">truncate</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">table</span><span style="color:#A6ACCD;"> account;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 时间: 457.847s</span></span>
<span class="line"><span style="color:#F78C6C;">call</span><span style="color:#A6ACCD;"> p1(</span><span style="color:#F78C6C;">10000000</span><span style="color:#A6ACCD;">);</span></span></code></pre></div><h3 id="覆盖索引-子查询" tabindex="-1">覆盖索引+子查询 <a class="header-anchor" href="#覆盖索引-子查询" aria-label="Permalink to &quot;覆盖索引+子查询&quot;">​</a></h3><blockquote><p>优化思路: <strong>通过创建 覆盖索引 能够比较好地提高性能，可以通过覆盖索引加子查询形式进行优化</strong>。</p></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_sku t , (</span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_sku </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">limit</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">2000000</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;">) a </span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> t.id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> a.id;</span></span></code></pre></div><blockquote><p>一个常见又非常头疼的问题就是 limit 2000000,10 ，此时需要MySQL排序前2000010 记录，仅仅返回2000000 - 2000010的记录，其他记录丢弃，查询排序的代价非常大 。</p></blockquote><blockquote><p>优化思路: 一般分页查询时，通过创建 覆盖索引能够比较好地提高性能，可以通过覆盖索引加子查询形式进行优化。因为我们有主键id，并且在上面建了索引，所以可以先在索引树中找到开始位置的 id值，再根据找到的id值查询。</p></blockquote><p>普通分页查询</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 1000000条数据</span></span>
<span class="line"><span style="color:#A6ACCD;">select count(1) from account;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 375ms</span></span>
<span class="line"><span style="color:#A6ACCD;">select * from tb_user limit 1999980,10;</span></span></code></pre></div><p>进行子查询的分页查询</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 单独查询id分页：180ms</span></span>
<span class="line"><span style="color:#A6ACCD;">select id from account order by id limit 1999980,10 ;</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">-- 子查询数据分页：120ms，查询结果和普通分页查询相同，但比他快</span></span>
<span class="line"><span style="color:#A6ACCD;">select s.* from account s, (select id from tb_user order by id limit 1999980,10) a</span></span>
<span class="line"><span style="color:#A6ACCD;">where s.id=a.id;</span></span></code></pre></div><p>因为以上的SQL，回表了100010次，实际上，我们只需要10条数据，也就是我们只需要10次回表其实就够了。因此，我们可以通过<strong>减少回表次数</strong>来优化。</p><p>如果我们把查询条件，转移回到<code>主键索引树</code>，那就可以减少回表次数啦。转移到主键索引树查询的话，查询条件得改为<code>主键id</code>了，之前SQL的<code>字段</code>这些条件咋办呢？抽到<strong>子查询</strong>那里嘛~</p><blockquote><p>子查询那里怎么抽的呢？因为二级索引叶子节点是有主键ID的，所以我们直接根据<code>update_time</code>来查主键ID即可，同时我们把 <code>limit 100000</code>的条件，也转移到子查询，完整SQL如下：</p></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 0.150s 很奇怪，如果不加上order by id，光查询id的话，返回值是乱序的</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> account </span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">&gt;=</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> t.id </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> account t </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">limit</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">990000</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">limit</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><h3 id="join延迟关联优化" tabindex="-1">join延迟关联优化 <a class="header-anchor" href="#join延迟关联优化" aria-label="Permalink to &quot;join延迟关联优化&quot;">​</a></h3><blockquote><p>延迟关联的优化思路，<strong>跟子查询的优化思路其实是一样的</strong>：都是把条件转移到主键索引树，然后减少回表。不同点是，<strong><code>延迟关联使用了inner join代替子查询</code></strong>。</p></blockquote><p>优化后的SQL如下：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 0.0159s</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user t1</span></span>
<span class="line"><span style="color:#F78C6C;">inner join</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> t.id </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user t </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">limit</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">990000</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">as</span><span style="color:#A6ACCD;"> t2</span></span>
<span class="line"><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> t1.id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> t2.id;</span></span></code></pre></div><p>再次示例</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 2.325s</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id,</span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;">,</span><span style="color:#C792EA;">money</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> account </span><span style="color:#F78C6C;">limit</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">9990000</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">20</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 1.820</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> account </span><span style="color:#F78C6C;">as</span><span style="color:#A6ACCD;"> a </span></span>
<span class="line"><span style="color:#F78C6C;">inner join</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> t.id </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> account t </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">limit</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">9990000</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">20</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">as</span><span style="color:#A6ACCD;"> b </span></span>
<span class="line"><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;"> a.id</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">b.id;</span></span></code></pre></div><h3 id="标签记录法" tabindex="-1">标签记录法 <a class="header-anchor" href="#标签记录法" aria-label="Permalink to &quot;标签记录法&quot;">​</a></h3><blockquote><p>limit 深分页问题的本质原因就是：<strong>偏移量（offset）越大，mysql就会扫描越多的行，然后再抛弃掉。这样就导致查询性能的下降</strong>。其实我们可以采用<strong>标签记录</strong>法，就是标记一下上次查询到哪一条了，下次再来查的时候，从该条开始往下扫描。<strong>就好像看书一样，上次看到哪里了，你就折叠一下或者夹个书签，下次来看，直接就翻到了</strong></p></blockquote><p>假设上一次记录到990000，则SQL可以修改为：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 0.014s</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> account </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1990000</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">limit</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>这个效率是最好的，无论怎么分页，耗时基本都是一致的，因为他执行完条件之后，都只扫描了10条数据。</p><blockquote><p>但是这种方式<strong>有局限性</strong>：<strong><code>需要一种类似连续自增的字段</code></strong>。只适合一页一页的分页，这样才能记住前一个分页的最后Id。如果用户跳着分页就有问题了，比如刚刚刷完第25页，马上跳到35页，数据就会不对。这种的适合场景是类似百度搜索或者腾讯新闻那种滚轮往下拉，不断拉取不断加载的情况。这种延迟加载会保证数据不会跳跃着获取。</p></blockquote><h3 id="between-and优化" tabindex="-1">between...and优化 <a class="header-anchor" href="#between-and优化" aria-label="Permalink to &quot;between...and优化&quot;">​</a></h3><blockquote><p>很多时候，可以将<code>limit</code>查询转换为已知位置的查询，这样MySQL通过范围扫描<code>between...and</code>，就能获得到对应的结果。如果知道边界值为990000，990010后，就可以这样优化：</p></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 0.015s</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> account </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">between</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">990000</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">and</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">990010</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> id;</span></span></code></pre></div><h3 id="降级策略" tabindex="-1">降级策略 <a class="header-anchor" href="#降级策略" aria-label="Permalink to &quot;降级策略&quot;">​</a></h3><blockquote><p>看了网上一个阿里的dba同学分享的方案：<strong>配置limit的偏移量和获取数一个最大值，超过这个最大值，就返回空数据。因为他觉得超过这个值你已经不是在分页了，而是在刷数据了，如果确认要找数据，应该输入合适条件来缩小范围，而不是一页一页分页</strong>。</p></blockquote><blockquote><p>这个跟我同事的想法大致一样：<strong>request的时候 如果offset大于某个数值就先返回一个4xx的错误</strong>。<strong>当晚我们应用上述第三个方案，对offset做一下限流，超过某个值，就返回空值</strong>。第二天使用第一种和第二种配合使用的方案对程序和数据库脚本进一步做了优化。</p></blockquote><blockquote><p>合理来说做任何功能都应该考虑极端情况，<strong>设计容量都应该涵盖极端边界测试</strong>。另外，<strong>该有的限流、降级也应该考虑进去</strong>。<strong>比如工具多线程调用，在短时间频率内8000次调用，可以使用计数服务判断并反馈用户调用过于频繁，直接给予断掉</strong>。</p></blockquote><h2 id="count优化" tabindex="-1">count优化 <a class="header-anchor" href="#count优化" aria-label="Permalink to &quot;count优化&quot;">​</a></h2><h3 id="为什么耗时" tabindex="-1">为什么耗时 <a class="header-anchor" href="#为什么耗时" aria-label="Permalink to &quot;为什么耗时&quot;">​</a></h3><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user ;</span></span></code></pre></div><p>在之前的测试中，我们发现，如果数据量很大，在执行count操作时，是非常耗时的。</p><blockquote><p>MyISAM 引擎把一个表的总行数存在了磁盘上，因此执行 count(*) 的时候会直接返回这个数，效率很高； 但是如果是带条件的count，MyISAM也慢。</p></blockquote><blockquote><p>InnoDB 引擎就麻烦了，它执行 count(*) 的时候，需要把数据一行一行地从引擎里面读出来，然后累积计数。</p></blockquote><blockquote><p>如果说要大幅度提升InnoDB表的count效率，主要的优化思路：自己计数(可以借助于redis这样的数据库进行,但是如果是带条件的count又比较麻烦了)。</p></blockquote><h3 id="count用法" tabindex="-1">count用法 <a class="header-anchor" href="#count用法" aria-label="Permalink to &quot;count用法&quot;">​</a></h3><blockquote><p>count() 是一个聚合函数，对于返回的结果集，一行行地判断，如果 count 函数的参数不是NULL，累计值就加 1，否则不加，最后返回累计值。用法：count（*）、count（主键）、count（字段）、count（数字）</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.8.30/202209211852958.png" alt="image-20220921185220849" style="zoom:80%;"><blockquote><p>按效率排序，<strong>count(字段) &lt; count(主键 id) &lt; count(1) ≈ count(*)，所以尽量使用 count(*)</strong>。</p></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 建议使用count(*)来进行计数</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user;</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user;</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">count</span><span style="color:#A6ACCD;">(id) </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> tb_user;</span></span></code></pre></div><h2 id="update优化" tabindex="-1">update优化 <a class="header-anchor" href="#update优化" aria-label="Permalink to &quot;update优化&quot;">​</a></h2><blockquote><p><strong>InnoDB的行锁是针对索引加的锁，不是针对记录加的锁 ,并且该索引不能失效，否则会从行锁升级为表锁</strong> 。<strong>因此update的where条件必须为索引列或者主键</strong></p></blockquote><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">create table course1(</span></span>
<span class="line"><span style="color:#A6ACCD;">    id int auto_increment comment &#39;主键ID&#39; primary key,</span></span>
<span class="line"><span style="color:#A6ACCD;">    name varchar(10) null comment &#39;课程名称&#39;</span></span>
<span class="line"><span style="color:#A6ACCD;">)comment &#39;课程表&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO course1 (name) VALUES (&#39;Java&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO course1 (name) VALUES (&#39;PHP&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO course1 (name) VALUES (&#39;MySQL&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO course1 (name) VALUES (&#39;Hadoop&#39;);</span></span></code></pre></div><h3 id="正常情况" tabindex="-1">正常情况 <a class="header-anchor" href="#正常情况" aria-label="Permalink to &quot;正常情况&quot;">​</a></h3><p>开启一个窗口</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 行锁,开启事务时行被锁住</span></span>
<span class="line"><span style="color:#A6ACCD;">begin ;</span></span>
<span class="line"><span style="color:#A6ACCD;">update course1 set name=&#39;javaee&#39; where id=1;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 去执行另一个窗口到update，然后这个窗口commit，另一个窗口再commit</span></span>
<span class="line"><span style="color:#A6ACCD;">commit ;</span></span></code></pre></div><p>另一个窗口，一切正常，完美不卡</p><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 行锁。开启事务时被锁住</span></span>
<span class="line"><span style="color:#A6ACCD;">begin ;</span></span>
<span class="line"><span style="color:#A6ACCD;">update course1 set name=&#39;kafka&#39; where id=4;</span></span>
<span class="line"><span style="color:#A6ACCD;">commit ;</span></span></code></pre></div><h3 id="不用索引列情况" tabindex="-1">不用索引列情况 <a class="header-anchor" href="#不用索引列情况" aria-label="Permalink to &quot;不用索引列情况&quot;">​</a></h3><blockquote><p>根据name字段进行更新(此时name不是索引列)</p></blockquote><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">begin ;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- name字段不是索引，变成表锁，直到这个窗口commit，另一个窗口才不卡住</span></span>
<span class="line"><span style="color:#A6ACCD;">update course1 set name=&#39;javase&#39; where name=&#39;javaee&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 先不提交</span></span></code></pre></div><blockquote><p>另一个窗口(虽然两个字段没有任何联系，但此时就是不能更新，因为已经变成了表锁)</p></blockquote><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">begin ;</span></span>
<span class="line"><span style="color:#A6ACCD;">-- 此时无法更新，直接卡住，等到上面的更新commit后才能更新</span></span>
<span class="line"><span style="color:#A6ACCD;">update course1 set name=&#39;kafka1&#39; where id=4;</span></span>
<span class="line"><span style="color:#A6ACCD;">commit ;</span></span></code></pre></div><blockquote><p>如果给name加上索引，再次执行如上操作，那么就不会出现上面的问题了</p></blockquote><div class="language-mysql"><button title="Copy Code" class="copy"></button><span class="lang">mysql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 给name字段添加索引</span></span>
<span class="line"><span style="color:#A6ACCD;">create index idx_name on course1(name);</span></span></code></pre></div><blockquote><p><strong>当我们开启多个事务，在执行上述SQL时，我们发现行锁升级为了表锁。 导致该update语句的性能大大降低</strong></p></blockquote></div></div></main><footer class="VPDocFooter" data-v-6b87e69f data-v-37656e44><!--[--><!--]--><!----><nav class="prev-next" data-v-37656e44><div class="pager" data-v-37656e44><a class="pager-link prev" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E5%9F%BA%E7%A1%80.html" data-v-37656e44><span class="desc" data-v-37656e44>Previous page</span><span class="title" data-v-37656e44>MySQL基础</span></a></div><div class="pager" data-v-37656e44><a class="pager-link next" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E4%BC%98%E5%8C%96.html" data-v-37656e44><span class="desc" data-v-37656e44>Next page</span><span class="title" data-v-37656e44>MySQL优化</span></a></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
    <script>window.__VP_HASH_MAP__=JSON.parse("{\"2、数据库_mysql_mysql面试_基础.md\":\"40da680a\",\"1、学前端_5、小程序_小程序项目.md\":\"60a1629b\",\"1、学前端_4、node_知识篇.md\":\"a7fb500e\",\"1、学前端_2、js_ts_es6 进阶.md\":\"6d07ba10\",\"1、学前端_3、vue_vue3_vue3进阶.md\":\"7ac622b4\",\"5、运维_jenkins.md\":\"929081f8\",\"1、学前端_2、js_ts_typescript.md\":\"875a4aa4\",\"2、数据库_mysql_mysql核心_设计.md\":\"7faf46d1\",\"2、数据库_mysql_mysql核心_基础.md\":\"d8e97f3e\",\"1、学前端_1、html_css_html基础.md\":\"7584d076\",\"1、学前端_5、专题篇_问题篇.md\":\"e893aaa2\",\"2、数据库_mysql_mysql面试_进阶.md\":\"f934806d\",\"3、springboot_运维_原理.md\":\"f4a39db6\",\"2、数据库_influxdb.md\":\"6e1711e1\",\"3、springboot_新特性.md\":\"cdf3e307\",\"mybatis_mybatisplus_jpa.md\":\"8e41681b\",\"1、学前端_5、小程序_小程序优化.md\":\"a2185198\",\"2、数据库_redis_redis基础.md\":\"856df0e0\",\"linux_实用脚本.md\":\"f2299dd5\",\"4、微服务_必备_分布式基础.md\":\"d49863d5\",\"2、数据库_redis_redis优化.md\":\"e66ae32f\",\"4、微服务_springsecurity_进阶篇.md\":\"235a8e9e\",\"5、运维_chatgpt.md\":\"10db3823\",\"2、数据库_mysql_分库分表.md\":\"e1c8a095\",\"start.md\":\"9bc1ff8d\",\"5、运维_github.md\":\"2ec6c735\",\"java学前端_css.md\":\"f11b47f0\",\"1、学前端_5、专题篇_知识篇.md\":\"a463ed8d\",\"linux_软件部署.md\":\"d6722925\",\"2、数据库_neo4j.md\":\"97ad22ac\",\"team.md\":\"ce467a6a\",\"nginx_实战篇.md\":\"7785486e\",\"index.md\":\"8c3ec167\",\"计算机基础_计算机网络_网络基础.md\":\"7a54a85d\",\"1、学前端_4、node_进阶篇.md\":\"60f6db69\",\"java_java集合.md\":\"a049b313\",\"1、学前端_3、vue_vue3_vue3高级.md\":\"614d1516\",\"1、学前端_5、小程序_微信小程序.md\":\"9a4be771\",\"5、运维_netty.md\":\"12ca0278\",\"2、数据库_mysql_mysql核心_运维.md\":\"83f97c16\",\"idea_vs code.md\":\"afdcb593\",\"java学前端_vue3_组件.md\":\"1086884e\",\"idea_chrome.md\":\"4a32afbc\",\"云原生_k8s.md\":\"db58e65a\",\"2、数据库_mysql_mysql核心_进阶.md\":\"61d16dff\",\"ssm_springbatch.md\":\"f799ab4a\",\"三高_分布式.md\":\"db1b8a1b\",\"2、数据库_elasticsearch_1、es基础.md\":\"04d17448\",\"linux_linux基础.md\":\"4b0bf394\",\"idea_idea插件.md\":\"fa86e45a\",\"可视化 _ 监控_可视化大屏.md\":\"004553bd\",\"2、数据库_mongodb_整合.md\":\"3c47d7f4\",\"4、微服务_springsecurity_基础篇.md\":\"534a3401\",\"4、微服务_进阶.md\":\"69095c58\",\"计算机基础_计算机基础_操作系统.md\":\"0f75d113\",\"可视化 _ 监控_zabbix.md\":\"71f2270e\",\"nginx_基础篇.md\":\"c7d8bb50\",\"1、学前端_4、node_项目实战.md\":\"bc5065b8\",\"2、数据库_redis_redis原理.md\":\"5cedf685\",\"可视化 _ 监控_监控基础.md\":\"ac56ce4d\",\"三高_高并发.md\":\"ea9ffc99\",\"2、数据库_redis_redis高级.md\":\"1d5872f6\",\"1、学前端_4、node_基础篇.md\":\"581cc13a\",\"2、数据库_mongodb_基础.md\":\"fb7a0a29\",\"idea_idea基础.md\":\"6f2f9638\",\"4、微服务_必备_sentinel.md\":\"2edfbf6c\",\"2、数据库_elasticsearch_3、es高级.md\":\"ef146606\",\"1、学前端_3、vue_vue3_vue3新语法.md\":\"8afd5409\",\"消息中间件_canal.md\":\"3949163c\",\"ssm_maven.md\":\"2c5e12ed\",\"4、微服务_springsecurity_高级篇.md\":\"882d3ff3\",\"linux_linux进阶.md\":\"188ef7b4\",\"计算机基础_设计模式_uml.md\":\"634ba256\",\"计算机基础_算法_leetcode.md\":\"77162fb9\",\"项目实战_小兔鲜_进阶篇1.md\":\"17c52c81\",\"1、学前端_2、js_ts_es6 基础.md\":\"fda3f18b\",\"项目实战_小兔鲜_进阶篇2.md\":\"a0f23006\",\"软件测试_测试基础.md\":\"8c1060cd\",\"2、数据库_redis_本地缓存.md\":\"00617fe6\",\"nginx_面试篇.md\":\"e3fb373a\",\"mybatis_mybatisplus_mybatis.md\":\"9239e0ad\",\"linux_shell.md\":\"ae53d83b\",\"2、数据库_mysql_mysql核心_优化.md\":\"36230425\",\"项目实战_项目推荐.md\":\"f9d97630\",\"mybatis_mybatisplus_mybatisplus.md\":\"0030fd35\",\"项目实战_百度地图_进阶篇.md\":\"c8b93267\",\"三高_高可用.md\":\"323840c5\",\"java_java新特性.md\":\"22abf56d\",\"软件测试_压力测试.md\":\"9ab44440\",\"java学前端_html_js.md\":\"e0fcd240\",\"2、数据库_redis_redis实战.md\":\"d6daeeab\",\"nginx_进阶篇.md\":\"e6b63195\",\"三高_秒杀.md\":\"3878bb64\",\"5、运维_git.md\":\"0264925c\",\"java_java进阶.md\":\"e79cb5b4\",\"并发 _ 多线程_基础篇.md\":\"7adbfac5\",\"项目实战_百度地图_基础篇.md\":\"8afa5954\",\"java学前端_react.md\":\"3ec827dd\",\"1、学前端_1、html_css_css基础.md\":\"01b56712\",\"项目实战_小兔鲜_基础篇.md\":\"646f5df5\",\"1、学前端_2、js_ts_js 基础.md\":\"cb13e36f\",\"可视化 _ 监控_监控进阶.md\":\"0cdbc292\",\"计算机基础_设计模式_基础篇.md\":\"51617287\",\"计算机基础_数据结构_基础篇.md\":\"b2bfd8d4\",\"项目实战_苍穹外卖_进阶篇.md\":\"48415e41\",\"ssm_spring.md\":\"ab514659\",\"消息中间件_rabbitmq.md\":\"45b1eb28\",\"1、学前端_1、html_css_网页进阶.md\":\"db998248\",\"消息中间件_kafka.md\":\"b747dabf\",\"云原生_docker.md\":\"983c7ba7\",\"4、微服务_必备_分布式锁.md\":\"5af1cf8d\",\"消息中间件_rocketmq.md\":\"d441da85\",\"项目实战_黑马头条_基础篇.md\":\"b05af3a6\",\"ssm_springmvc.md\":\"81b9714f\",\"项目实战_支付.md\":\"1d7407dd\",\"项目实战_黑马头条_进阶篇2.md\":\"bff0015b\",\"项目实战_黑马头条_进阶篇.md\":\"19f18388\",\"java学前端_vue2_组件.md\":\"58c6b1df\",\"3、springboot_基础篇.md\":\"529c66f4\",\"3、springboot_应用篇.md\":\"8b92aa61\",\"项目实战_黑马头条_高级篇.md\":\"227c08c1\",\"1、学前端_5、小程序_uniapp.md\":\"71a282b4\",\"项目实战_云尚办公_基础篇.md\":\"1fe188ba\",\"并发 _ 多线程_并发完善.md\":\"26619c46\",\"1、学前端_2、js_ts_js 进阶.md\":\"657dfb8f\",\"java_java高级.md\":\"23782d1a\",\"java_java基础.md\":\"86d67c77\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"VitePress\",\"description\":\"A VitePress site\",\"base\":\"/notebook/\",\"head\":[],\"appearance\":true,\"themeConfig\":{\"algolia\":{\"appId\":\"DW7O63I9IR\",\"apiKey\":\"f8ed758cdb288a8b06542bc35923c1a1\",\"indexName\":\"notebook\"},\"sidebar\":[{\"text\":\"Java\",\"collapsed\":true,\"items\":[{\"text\":\"Java基础\",\"link\":\"/Java/Java基础\"},{\"text\":\"Java新特性\",\"link\":\"/Java/Java新特性\"},{\"text\":\"Java进阶\",\"link\":\"/Java/Java进阶\"},{\"text\":\"Java集合\",\"link\":\"/Java/Java集合\"},{\"text\":\"Java高级\",\"link\":\"/Java/Java高级\"}]},{\"text\":\"Linux\",\"collapsed\":true,\"items\":[{\"text\":\"Linux基础\",\"link\":\"/Linux/Linux基础\"},{\"text\":\"Linux新特性\",\"link\":\"/Linux/Linux进阶\"},{\"text\":\"Shell脚本\",\"link\":\"/Linux/Shell\"},{\"text\":\"实用脚本\",\"link\":\"/Linux/实用脚本\"},{\"text\":\"软件部署\",\"link\":\"/Linux/软件部署\"}]},{\"text\":\"Nginx\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/Nginx/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/Nginx/进阶篇\"},{\"text\":\"实战篇\",\"link\":\"/Nginx/实战篇\"},{\"text\":\"面试篇\",\"link\":\"/Nginx/面试篇\"}]},{\"text\":\"SSM\",\"collapsed\":true,\"items\":[{\"text\":\"Maven\",\"link\":\"/SSM/Maven\"},{\"text\":\"Spring\",\"link\":\"/SSM/Spring\"},{\"text\":\"SpringMVC\",\"link\":\"/SSM/SpringMVC\"},{\"text\":\"SpringBatch\",\"link\":\"/SSM/SpringBatch\"}]},{\"text\":\"SpringBoot\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/3、SpringBoot/基础篇\"},{\"text\":\"应用篇\",\"link\":\"/3、SpringBoot/应用篇\"},{\"text\":\"新特性\",\"link\":\"/3、SpringBoot/新特性\"},{\"text\":\"运维&原理\",\"link\":\"/3、SpringBoot/运维&原理\"}]},{\"text\":\"SpringCloud\",\"collapsed\":true,\"items\":[{\"text\":\"SpringCloud\",\"link\":\"/4、微服务/进阶\"},{\"text\":\"Sentinel\",\"link\":\"/4、微服务/必备/Sentinel\"}]},{\"text\":\"SpringSecurity\",\"collapsed\":true,\"items\":[{\"text\":\"SpringSecurity基础篇\",\"link\":\"/4、微服务/SpringSecurity/基础篇\"},{\"text\":\"SpringSecurity进阶篇\",\"link\":\"/4、微服务/SpringSecurity/进阶篇\"},{\"text\":\"SpringSecurity高级篇\",\"link\":\"/4、微服务/SpringSecurity/高级篇\"}]},{\"text\":\"Mybatis & MybatisPlus\",\"collapsed\":true,\"items\":[{\"text\":\"Mybatis\",\"link\":\"/Mybatis&MybatisPlus/Mybatis\"},{\"text\":\"MybatisPlus\",\"link\":\"/Mybatis&MybatisPlus/MybatisPlus\"},{\"text\":\"JPA\",\"link\":\"/Mybatis&MybatisPlus/JPA\"}]},{\"text\":\"Git & ChatGPT\",\"collapsed\":true,\"items\":[{\"text\":\"Git\",\"link\":\"/5、运维/Git\"},{\"text\":\"Github\",\"link\":\"/5、运维/Github\"},{\"text\":\"ChatGPT\",\"link\":\"/5、运维/ChatGPT\"},{\"text\":\"Jenkins\",\"link\":\"/5、运维/Jenkins\"},{\"text\":\"Netty\",\"link\":\"/5、运维/Netty\"}]},{\"text\":\"数据库\",\"collapsed\":true,\"items\":[{\"text\":\"MySQL\",\"collapsed\":true,\"items\":[{\"text\":\"MySQL基础\",\"link\":\"/2、数据库/MySQL/MySQL核心/基础\"},{\"text\":\"MySQL进阶\",\"link\":\"/2、数据库/MySQL/MySQL核心/进阶\"},{\"text\":\"MySQL优化\",\"link\":\"/2、数据库/MySQL/MySQL核心/优化\"},{\"text\":\"MySQL设计\",\"link\":\"/2、数据库/MySQL/MySQL核心/设计\"},{\"text\":\"MySQL运维\",\"link\":\"/2、数据库/MySQL/MySQL核心/运维\"},{\"text\":\"分库分表\",\"link\":\"/2、数据库/MySQL/分库分表\"}]},{\"text\":\"Redis\",\"collapsed\":true,\"items\":[{\"text\":\"Redis基础\",\"link\":\"/2、数据库/Redis/Redis基础\"},{\"text\":\"Redis优化\",\"link\":\"/2、数据库/Redis/Redis优化\"},{\"text\":\"Redis原理\",\"link\":\"/2、数据库/Redis/Redis原理\"},{\"text\":\"Redis高级\",\"link\":\"/2、数据库/Redis/Redis高级\"},{\"text\":\"Redis实战\",\"link\":\"/2、数据库/Redis/Redis实战\"},{\"text\":\"本地缓存\",\"link\":\"/2、数据库/Redis/本地缓存\"}]},{\"text\":\"MongoDB\",\"collapsed\":true,\"items\":[{\"text\":\"MongoDB基础\",\"link\":\"/2、数据库/MongoDB/基础\"},{\"text\":\"MongoDB进阶\",\"link\":\"/2、数据库/MongoDB/整合\"}]},{\"text\":\"ElasticSearch\",\"collapsed\":true,\"items\":[{\"text\":\"ES基础\",\"link\":\"/2、数据库/ElasticSearch/1、ES基础\"},{\"text\":\"ES高级\",\"link\":\"/2、数据库/ElasticSearch/3、ES高级\"}]},{\"text\":\"InfluxDB\",\"link\":\"/2、数据库/influxdb\"},{\"text\":\"Neo4j\",\"link\":\"/2、数据库/Neo4j\"}]},{\"text\":\"高并发 & 秒杀 & 分布式\",\"collapsed\":true,\"items\":[{\"text\":\"分布式理论\",\"link\":\"/三高/分布式\"},{\"text\":\"分布式锁\",\"link\":\"/4、微服务/必备/分布式锁\"},{\"text\":\"秒杀\",\"link\":\"/三高/秒杀\"},{\"text\":\"高可用\",\"link\":\"/三高/高可用\"},{\"text\":\"高并发\",\"link\":\"/三高/高并发\"}]},{\"text\":\"云原生\",\"collapsed\":true,\"items\":[{\"text\":\"Docker\",\"link\":\"/云原生/Docker\"},{\"text\":\"K8S\",\"link\":\"/云原生/K8S\"}]},{\"text\":\"可视化 & 监控\",\"collapsed\":true,\"items\":[{\"text\":\"监控基础\",\"link\":\"/可视化 & 监控/监控基础\"},{\"text\":\"监控进阶\",\"link\":\"/可视化 & 监控/监控进阶\"},{\"text\":\"可视化大屏\",\"link\":\"/可视化 & 监控/可视化大屏\"},{\"text\":\"Zabbix\",\"link\":\"/可视化 & 监控/Zabbix\"}]},{\"text\":\"学前端\",\"collapsed\":true,\"items\":[{\"text\":\"HTML+CSS\",\"collapsed\":true,\"items\":[{\"text\":\"HTML基础\",\"link\":\"/1、学前端/1、HTML+CSS/HTML基础\"},{\"text\":\"CSS基础\",\"link\":\"/1、学前端/1、HTML+CSS/CSS基础\"},{\"text\":\"网页进阶\",\"link\":\"/1、学前端/1、HTML+CSS/网页进阶\"}]},{\"text\":\"JS+TS\",\"collapsed\":true,\"items\":[{\"text\":\"JS基础\",\"link\":\"/1、学前端/2、JS+TS/JS 基础\"},{\"text\":\"JS进阶\",\"link\":\"/1、学前端/2、JS+TS/JS 进阶\"},{\"text\":\"ES6基础\",\"link\":\"/1、学前端/2、JS+TS/ES6 基础\"},{\"text\":\"ES6进阶\",\"link\":\"/1、学前端/2、JS+TS/ES6 进阶\"},{\"text\":\"TS基础\",\"link\":\"/1、学前端/2、JS+TS/TypeScript\"}]},{\"text\":\"NodeJS\",\"collapsed\":true,\"items\":[{\"text\":\"Node基础\",\"link\":\"/1、学前端/4、Node/基础篇\"},{\"text\":\"Node进阶\",\"link\":\"/1、学前端/4、Node/进阶篇\"},{\"text\":\"项目实战\",\"link\":\"/1、学前端/4、Node/项目实战\"}]},{\"text\":\"Vue\",\"collapsed\":true,\"items\":[{\"text\":\"Vue3进阶\",\"link\":\"/1、学前端/3、Vue/Vue3/Vue3进阶\"},{\"text\":\"Vue3高级\",\"link\":\"/1、学前端/3、Vue/Vue3/Vue3高级\"},{\"text\":\"Vue3新语法\",\"link\":\"/1、学前端/3、Vue/Vue3/Vue3新语法\"},{\"text\":\"项目实战\",\"link\":\"/1、学前端/3、Vue/Vue2/Vue2项目\"}]},{\"text\":\"小程序\",\"collapsed\":true,\"items\":[{\"text\":\"小程序基础\",\"link\":\"/1、学前端/5、小程序/微信小程序\"},{\"text\":\"小程序优化\",\"link\":\"/1、学前端/5、小程序/小程序优化\"},{\"text\":\"uniapp\",\"link\":\"/1、学前端/5、小程序/uniapp\"},{\"text\":\"项目实战\",\"link\":\"/1、学前端/5、小程序/小程序项目\"}]}]},{\"text\":\"计算机基础\",\"collapsed\":true,\"items\":[{\"text\":\"数据结构\",\"link\":\"/计算机基础/数据结构/基础篇\"},{\"text\":\"操作系统\",\"link\":\"/计算机基础/计算机基础/操作系统\"},{\"text\":\"设计模式\",\"link\":\"/计算机基础/设计模式/基础篇\"},{\"text\":\"计算机网络\",\"link\":\"/计算机基础/计算机网络/网络基础\"},{\"text\":\"UML\",\"link\":\"/计算机基础/设计模式/UML\"},{\"text\":\"LeetCode\",\"link\":\"/计算机基础/算法/LeetCode\"}]},{\"text\":\"项目实战\",\"collapsed\":true,\"items\":[{\"text\":\"云尚办公\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/云尚办公/基础篇\"}]},{\"text\":\"小兔鲜\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/小兔鲜/基础篇\"},{\"text\":\"进阶篇1\",\"link\":\"/项目实战/小兔鲜/进阶篇1\"},{\"text\":\"进阶篇2\",\"link\":\"/项目实战/小兔鲜/进阶篇2\"}]},{\"text\":\"地图\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/百度地图/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/项目实战/百度地图/进阶篇\"}]},{\"text\":\"苍穹外卖\",\"collapsed\":true,\"items\":[{\"text\":\"进阶篇\",\"link\":\"/项目实战/苍穹外卖/进阶篇\"}]},{\"text\":\"黑马头条\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/黑马头条/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/项目实战/黑马头条/进阶篇\"},{\"text\":\"进阶篇2\",\"link\":\"/项目实战/黑马头条/进阶篇2\"},{\"text\":\"高级篇\",\"link\":\"/项目实战/黑马头条/高级篇\"}]},{\"text\":\"支付\",\"link\":\"/项目实战/支付\"},{\"text\":\"项目推荐\",\"link\":\"/项目实战/项目推荐\"}]},{\"text\":\"团队成员\",\"link\":\"/team\"}],\"siteTitle\":\"任硕的文档\",\"logo\":\"/Vue.png\",\"nav\":[{\"text\":\"Java学前端\",\"items\":[{\"items\":[{\"text\":\"HTML+JS\",\"link\":\"/Java学前端/HTML+JS\"},{\"text\":\"CSS\",\"link\":\"/Java学前端/CSS\"},{\"text\":\"Vue2+组件\",\"link\":\"/Java学前端/Vue2+组件\"},{\"text\":\"Vue3+组件\",\"link\":\"/Java学前端/Vue3+组件\"},{\"text\":\"React\",\"link\":\"/Java学前端/React\"}]}],\"activeMatch\":\"/Java/\"},{\"text\":\"软件测试\",\"items\":[{\"items\":[{\"text\":\"测试基础\",\"link\":\"/软件测试/测试基础\"},{\"text\":\"压力测试\",\"link\":\"/软件测试/压力测试\"}]}]},{\"text\":\"多线程\",\"items\":[{\"items\":[{\"text\":\"基础篇\",\"link\":\"/并发 & 多线程/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/并发 & 多线程/并发完善\"}]}]},{\"text\":\"开发工具\",\"items\":[{\"items\":[{\"text\":\"Chrome\",\"link\":\"/IDEA/Chrome\"},{\"text\":\"IDEA基础\",\"link\":\"/IDEA/IDEA基础\"},{\"text\":\"IDEA插件\",\"link\":\"/IDEA/IDEA插件\"},{\"text\":\"VS Code\",\"link\":\"/IDEA/VS Code\"}]}]},{\"text\":\"消息中间件\",\"items\":[{\"items\":[{\"text\":\"RabbitMQ\",\"link\":\"/消息中间件/RabbitMQ\"},{\"text\":\"RocketMQ\",\"link\":\"/消息中间件/RocketMQ\"},{\"text\":\"Kafka\",\"link\":\"/消息中间件/Kafka\"},{\"text\":\"Canal\",\"link\":\"/消息中间件/Canal\"}]}]}],\"socialLinks\":[{\"icon\":\"github\",\"link\":\"https://github.com/renshuo123/renshuo123.github.io\"},{\"icon\":\"twitter\",\"link\":\"#\"},{\"icon\":{\"svg\":\"<svg t=\\\"1676028692954\\\" class=\\\"icon\\\" ...</path></svg>\"},\"link\":\"https://github.com/\"}]},\"locales\":{},\"scrollOffset\":90,\"cleanUrls\":false}");</script>
    
  </body>
</html>